[med-svn] [dicoogle] 11/13: New upstream version 2.5.0

Andreas Tille tille at debian.org
Mon Dec 25 11:13:47 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository dicoogle.

commit 975a2762a1fb91056d37932c608c87c0fe231ba6
Author: Andreas Tille <tille at debian.org>
Date:   Mon Dec 25 12:12:34 2017 +0100

    New upstream version 2.5.0
---
 .gitignore                                         |    20 +
 README.md                                          |   198 +
 debian/changelog                                   |     5 -
 debian/compat                                      |     1 -
 debian/control                                     |    24 -
 debian/copyright                                   |    25 -
 debian/rules                                       |     9 -
 debian/source/format                               |     1 -
 debian/watch                                       |     3 -
 dicoogle/.gitignore                                |    22 +
 dicoogle/pom.xml                                   |   388 +
 .../java/pt/ua/dicoogle/DicomLog/LogDICOM.java     |    85 +
 .../main/java/pt/ua/dicoogle/DicomLog/LogLine.java |   134 +
 .../main/java/pt/ua/dicoogle/DicomLog/LogXML.java  |   199 +
 .../main/java/pt/ua/dicoogle/ExceptionHandler.java |    78 +
 dicoogle/src/main/java/pt/ua/dicoogle/LICENSE      |   674 +
 dicoogle/src/main/java/pt/ua/dicoogle/Main.java    |   367 +
 .../src/main/java/pt/ua/dicoogle/SystemInfo.java   |    58 +
 .../pt/ua/dicoogle/common/ExtensionFilter.java     |    66 +
 .../java/pt/ua/dicoogle/config/Client_Truststore   |   Bin 0 -> 620 bytes
 .../java/pt/ua/dicoogle/config/Server_Keystore     |   Bin 0 -> 1328 bytes
 .../java/pt/ua/dicoogle/config/services.properties |     2 +
 .../main/java/pt/ua/dicoogle/core/AsyncIndex.java  |   101 +
 .../java/pt/ua/dicoogle/core/ClientSettings.java   |   159 +
 .../pt/ua/dicoogle/core/ExportDataSupport.java     |   238 +
 .../ua/dicoogle/core/QueryExpressionBuilder.java   |   203 +
 .../pt/ua/dicoogle/core/QueryHistoryEntry.java     |    37 +
 .../pt/ua/dicoogle/core/QueryHistorySupport.java   |   113 +
 .../pt/ua/dicoogle/core/QueryResultRecord.java     |    90 +
 .../java/pt/ua/dicoogle/core/ServerSettings.java   |  1338 ++
 .../src/main/java/pt/ua/dicoogle/core/TagsXML.java |   379 +
 .../src/main/java/pt/ua/dicoogle/core/UnZip.java   |   118 +
 .../src/main/java/pt/ua/dicoogle/core/Version.java |    50 +
 .../java/pt/ua/dicoogle/core/XMLClientSupport.java |   288 +
 .../main/java/pt/ua/dicoogle/core/XMLSupport.java  |  1672 ++
 .../src/main/java/pt/ua/dicoogle/core/Zip.java     |   208 +
 .../ua/dicoogle/core/dicom/PrivateDictionary.java  |   109 +
 .../java/pt/ua/dicoogle/core/dicom/SearchURI.java  |    78 +
 .../java/pt/ua/dicoogle/core/dim/ConcatTags.java   |   142 +
 .../java/pt/ua/dicoogle/core/dim/DIMGeneric.java   |   556 +
 .../main/java/pt/ua/dicoogle/core/dim/Patient.java |   169 +
 .../main/java/pt/ua/dicoogle/core/dim/Serie.java   |   374 +
 .../main/java/pt/ua/dicoogle/core/dim/Study.java   |   244 +
 .../exceptions/CFindNotSupportedException.java     |    28 +
 .../dicoogle/core/query/ExportToCSVQueryTask.java  |   131 +
 .../dicoogle/plugins/DefaultFileStoragePlugin.java |   213 +
 .../ua/dicoogle/plugins/DicooglePlatformProxy.java |   154 +
 .../java/pt/ua/dicoogle/plugins/NetworkMember.java |    47 +
 .../pt/ua/dicoogle/plugins/PluginController.java   |   829 +
 .../java/pt/ua/dicoogle/plugins/PluginFactory.java |    58 +
 .../pt/ua/dicoogle/plugins/PluginPanelLoader.java  |   124 +
 .../plugins/webui/PluginFormatException.java       |    41 +
 .../pt/ua/dicoogle/plugins/webui/WebUIPlugin.java  |   182 +
 .../dicoogle/plugins/webui/WebUIPluginManager.java |   266 +
 .../rGUI/MultihomeRMIClientSocketFactory.java      |   154 +
 .../rGUI/MultihomeSslRMIClientSocketFactory.java   |   129 +
 .../ua/dicoogle/rGUI/RFileBrowser/FileAction.java  |    37 +
 .../rGUI/RFileBrowser/IRemoteFileSystem.java       |    73 +
 .../rGUI/RFileBrowser/IconListRenderer.java        |    81 +
 .../ua/dicoogle/rGUI/RFileBrowser/RemoteFile.java  |   181 +
 .../rGUI/RFileBrowser/RemoteFileChooser.form       |   195 +
 .../rGUI/RFileBrowser/RemoteFileChooser.java       |   372 +
 .../rGUI/RFileBrowser/RemoteFileSystemServer.java  |   227 +
 .../java/pt/ua/dicoogle/rGUI/client/AdminRefs.java |   357 +
 .../pt/ua/dicoogle/rGUI/client/ClientCore.java     |   257 +
 .../pt/ua/dicoogle/rGUI/client/ConnectServer.java  |   163 +
 .../client/UIHelper/AllowBlankMaskFormatter.java   |   101 +
 .../dicoogle/rGUI/client/UIHelper/DisplayJAI.java  |   159 +
 .../dicoogle/rGUI/client/UIHelper/OSXAdapter.java  |   224 +
 .../rGUI/client/UIHelper/PanelBuiltFromXML.java    |   176 +
 .../client/UIHelper/PanelPluginsController.java    |    62 +
 .../dicoogle/rGUI/client/UIHelper/Result2Tree.java |   868 +
 .../client/UIHelper/ServerMessagesManager.java     |    72 +
 .../rGUI/client/UIHelper/TrayIconCreator.java      |    57 +
 .../java/pt/ua/dicoogle/rGUI/client/UserRefs.java  |   111 +
 .../dicoogle/rGUI/client/signals/LogsSignal.java   |    65 +
 .../rGUI/client/signals/PendingMessagesSignal.java |    57 +
 .../dicoogle/rGUI/client/signals/SearchSignal.java |    83 +
 .../rGUI/client/signals/TaskListSignal.java        |    49 +
 .../rGUI/client/windows/ActiveSessions.form        |   111 +
 .../rGUI/client/windows/ActiveSessions.java        |   230 +
 .../rGUI/client/windows/ChangePassword.form        |   158 +
 .../rGUI/client/windows/ChangePassword.java        |   278 +
 .../rGUI/client/windows/ClientOptions.form         |   354 +
 .../rGUI/client/windows/ClientOptions.java         |   485 +
 .../rGUI/client/windows/ConnectWindow.form         |   201 +
 .../rGUI/client/windows/ConnectWindow.java         |   403 +
 .../ua/dicoogle/rGUI/client/windows/DicomSend.form |   195 +
 .../ua/dicoogle/rGUI/client/windows/DicomSend.java |   356 +
 .../dicoogle/rGUI/client/windows/ExportData.form   |   336 +
 .../dicoogle/rGUI/client/windows/ExportData.java   |   595 +
 .../rGUI/client/windows/FileAlreadyIndexed.form    |   139 +
 .../rGUI/client/windows/FileAlreadyIndexed.java    |   313 +
 .../rGUI/client/windows/IndexedMetaData.form       |    97 +
 .../rGUI/client/windows/IndexedMetaData.java       |   337 +
 .../pt/ua/dicoogle/rGUI/client/windows/Logs.form   |   160 +
 .../pt/ua/dicoogle/rGUI/client/windows/Logs.java   |   280 +
 .../dicoogle/rGUI/client/windows/MainWindow.form   |  1436 ++
 .../dicoogle/rGUI/client/windows/MainWindow.java   |  3304 ++++
 .../ua/dicoogle/rGUI/client/windows/QRServers.form |   215 +
 .../ua/dicoogle/rGUI/client/windows/QRServers.java |   398 +
 .../dicoogle/rGUI/client/windows/QueryHistory.form |   142 +
 .../dicoogle/rGUI/client/windows/QueryHistory.java |   263 +
 .../dicoogle/rGUI/client/windows/SearchTips.form   |   191 +
 .../dicoogle/rGUI/client/windows/SearchTips.java   |   309 +
 .../ua/dicoogle/rGUI/client/windows/Services.form  |   397 +
 .../ua/dicoogle/rGUI/client/windows/Services.java  |   854 +
 .../ua/dicoogle/rGUI/client/windows/TaskList.form  |    29 +
 .../ua/dicoogle/rGUI/client/windows/TaskList.java  |   139 +
 .../dicoogle/rGUI/client/windows/UsersManager.form |   221 +
 .../dicoogle/rGUI/client/windows/UsersManager.java |   406 +
 .../dicoogle/rGUI/fileTransfer/FileReceiver.java   |   130 +
 .../ua/dicoogle/rGUI/fileTransfer/FileSender.java  |   156 +
 .../dicoogle/rGUI/fileTransfer/TransferStatus.form |   143 +
 .../dicoogle/rGUI/fileTransfer/TransferStatus.java |   239 +
 .../pt/ua/dicoogle/rGUI/interfaces/IAdmin.java     |   113 +
 .../pt/ua/dicoogle/rGUI/interfaces/ILogin.java     |    36 +
 .../java/pt/ua/dicoogle/rGUI/interfaces/IUser.java |    58 +
 .../rGUI/interfaces/controllers/IAccessList.java   |    41 +
 .../interfaces/controllers/IActiveSessions.java    |    38 +
 .../rGUI/interfaces/controllers/IDicomSend.java    |    37 +
 .../rGUI/interfaces/controllers/IDirectory.java    |   112 +
 .../rGUI/interfaces/controllers/IIndexOptions.java |    66 +
 .../rGUI/interfaces/controllers/ILogs.java         |    46 +
 .../interfaces/controllers/INetworkInterfaces.java |    37 +
 .../interfaces/controllers/IPendingMessages.java   |    38 +
 .../controllers/IPluginControllerAdmin.java        |    52 +
 .../controllers/IPluginControllerUser.java         |    55 +
 .../rGUI/interfaces/controllers/IQRServers.java    |    46 +
 .../interfaces/controllers/IQueryRetrieve.java     |    60 +
 .../rGUI/interfaces/controllers/ISOPClass.java     |    52 +
 .../rGUI/interfaces/controllers/ISearch.java       |    74 +
 .../rGUI/interfaces/controllers/IServices.java     |    72 +
 .../rGUI/interfaces/controllers/IStartupServ.java  |    64 +
 .../rGUI/interfaces/controllers/ITaskList.java     |    39 +
 .../rGUI/interfaces/controllers/IUsersManager.java |    43 +
 .../rGUI/interfaces/signals/ILogsSignal.java       |    41 +
 .../interfaces/signals/IPendingMessagesSignal.java |    40 +
 .../rGUI/interfaces/signals/ISearchSignal.java     |    43 +
 .../rGUI/interfaces/signals/ITaskListSignal.java   |    32 +
 .../java/pt/ua/dicoogle/rGUI/package-info.java     |     3 +
 .../pt/ua/dicoogle/rGUI/server/AdminFeatures.java  |   545 +
 .../pt/ua/dicoogle/rGUI/server/DicoogleScan.java   |    79 +
 .../java/pt/ua/dicoogle/rGUI/server/GUIServer.java |   137 +
 .../java/pt/ua/dicoogle/rGUI/server/Login.java     |   119 +
 .../pt/ua/dicoogle/rGUI/server/SearchHelper.java   |   218 +
 .../pt/ua/dicoogle/rGUI/server/UserFeatures.java   |   206 +
 .../rGUI/server/controllers/AccessList.java        |   169 +
 .../rGUI/server/controllers/DicomSend.java         |    97 +
 .../rGUI/server/controllers/DirectorySettings.java |   325 +
 .../rGUI/server/controllers/IndexOptions.java      |   299 +
 .../ua/dicoogle/rGUI/server/controllers/Logs.java  |   251 +
 .../rGUI/server/controllers/NetworkInterfaces.java |    87 +
 .../rGUI/server/controllers/PendingMessages.java   |   142 +
 .../server/controllers/PluginController4Admin.java |   129 +
 .../server/controllers/PluginController4user.java  |    98 +
 .../rGUI/server/controllers/QRServers.java         |   122 +
 .../rGUI/server/controllers/QueryRetrieve.java     |   183 +
 .../dicoogle/rGUI/server/controllers/SOPClass.java |   563 +
 .../dicoogle/rGUI/server/controllers/Search.java   |   517 +
 .../rGUI/server/controllers/StartupServices.java   |   241 +
 .../dicoogle/rGUI/server/controllers/TaskList.java |    91 +
 .../rGUI/server/controllers/UsersManager.java      |   198 +
 .../pt/ua/dicoogle/server/ControlServices.java     |   280 +
 .../pt/ua/dicoogle/server/DicomDirCreator.java     |   181 +
 .../java/pt/ua/dicoogle/server/DicomNetwork.java   |   250 +
 .../java/pt/ua/dicoogle/server/FileWatcher.java    |    64 +
 .../dicoogle/server/LegacyRestletApplication.java  |    81 +
 .../dicoogle/server/PluginRestletApplication.java  |    76 +
 .../java/pt/ua/dicoogle/server/RSIStorage.java     |   517 +
 .../main/java/pt/ua/dicoogle/server/SOPList.java   |   372 +
 .../pt/ua/dicoogle/server/SearchDicomResult.java   |   411 +
 .../pt/ua/dicoogle/server/TransfersStorage.java    |   225 +
 .../pt/ua/dicoogle/server/callbacks/LogEvent.java  |    35 +
 .../dicoogle/server/callbacks/LogEventAfter.java   |    28 +
 .../dicoogle/server/callbacks/LogEventBefore.java  |    31 +
 .../server/queryretrieve/CFindBuilder.java         |   386 +
 .../server/queryretrieve/CFindServiceSCP.java      |   199 +
 .../server/queryretrieve/CMoveService.java         |    85 +
 .../server/queryretrieve/CMoveServiceSCP.java      |   323 +
 .../dicoogle/server/queryretrieve/CallDCMSend.java |   136 +
 .../ua/dicoogle/server/queryretrieve/DcmSnd.java   |   931 +
 .../ua/dicoogle/server/queryretrieve/DcmSndV2.java |   908 +
 .../server/queryretrieve/DicomEchoReply.java       |   448 +
 .../server/queryretrieve/EchoReplyService.java     |    99 +
 .../ua/dicoogle/server/queryretrieve/Filter.java   |    92 +
 .../ua/dicoogle/server/queryretrieve/FindRSP.java  |   331 +
 .../ua/dicoogle/server/queryretrieve/MoveRSP.java  |   108 +
 .../server/queryretrieve/QueryRetrieve.java        |   214 +
 .../pt/ua/dicoogle/server/users/HashService.java   |    59 +
 .../java/pt/ua/dicoogle/server/users/Role.java     |    67 +
 .../pt/ua/dicoogle/server/users/RoleManager.java   |    35 +
 .../pt/ua/dicoogle/server/users/RolesStruct.java   |    72 +
 .../java/pt/ua/dicoogle/server/users/RolesXML.java |   243 +
 .../java/pt/ua/dicoogle/server/users/User.java     |   135 +
 .../ua/dicoogle/server/users/UserFileHandle.java   |   161 +
 .../java/pt/ua/dicoogle/server/users/UserON.java   |   114 +
 .../ua/dicoogle/server/users/UserRoleManager.java  |    28 +
 .../pt/ua/dicoogle/server/users/UserSessions.java  |   232 +
 .../ua/dicoogle/server/users/UserSessionsLog.java  |   173 +
 .../pt/ua/dicoogle/server/users/UsersStruct.java   |   138 +
 .../java/pt/ua/dicoogle/server/users/UsersXML.java |   259 +
 .../dicoogle/server/web/AbstractCacheFilter.java   |    80 +
 .../java/pt/ua/dicoogle/server/web/CORSFilter.java |    98 +
 .../pt/ua/dicoogle/server/web/DicoogleWeb.java     |   357 +
 .../server/web/FirstResponserQueryHolder.java      |    86 +
 .../dicoogle/server/web/PluginsServlet.java.orig   |   116 +
 .../dicoogle/server/web/auth/Authentication.java   |   118 +
 .../pt/ua/dicoogle/server/web/auth/LoggedIn.java   |    61 +
 .../dicoogle/server/web/auth/LoggedInStatus.java   |    95 +
 .../pt/ua/dicoogle/server/web/auth/Session.java    |   289 +
 .../ua/dicoogle/server/web/dicom/Convert2PNG.java  |   391 +
 .../ua/dicoogle/server/web/dicom/Information.java  |   341 +
 .../pt/ua/dicoogle/server/web/dicom/Search.java    |   906 +
 .../ua/dicoogle/server/web/dicom/SearchHolder.java |   181 +
 .../server/web/dicom/SearchResultsTree.java        |    28 +
 .../dicoogle/server/web/management/Dicoogle.java   |   844 +
 .../ua/dicoogle/server/web/management/Indexer.java |   275 +
 .../dicoogle/server/web/management/Services.java   |  1196 ++
 .../dicoogle/server/web/rest/ExamTimeResource.java |    87 +
 .../ua/dicoogle/server/web/rest/ExtResource.java   |    35 +
 .../ua/dicoogle/server/web/rest/ForceIndexing.java |    91 +
 .../server/web/rest/RestCountQueryResults.java     |    64 +
 .../server/web/rest/RestDcmImageResource.java      |   125 +
 .../dicoogle/server/web/rest/RestDimResource.java  |   235 +
 .../dicoogle/server/web/rest/RestDumpResource.java |   132 +
 .../ua/dicoogle/server/web/rest/RestEnumField.java |    91 +
 .../dicoogle/server/web/rest/RestFileResource.java |   119 +
 .../server/web/rest/RestImageResource.java         |   123 +
 .../dicoogle/server/web/rest/RestTagsResource.java |    67 +
 .../dicoogle/server/web/rest/RestWADOResource.java |    65 +
 .../ua/dicoogle/server/web/rest/TestResource.java  |    74 +
 .../dicoogle/server/web/rest/VersionResource.java  |    49 +
 .../server/web/rest/elements/ExamTimeCore.java     |   119 +
 .../web/rest/elements/FileDownloadUtils.java       |   135 +
 .../server/web/rest/elements/JaxbStrList.java      |    51 +
 .../server/web/rest/elements/TExamTime.java        |   246 +
 .../web/servlets/ExportCSVToFILEServlet.java       |   161 +
 .../server/web/servlets/ExportToCSVServlet.java    |   146 +
 .../dicoogle/server/web/servlets/ImageServlet.java |   252 +
 .../server/web/servlets/IndexerServlet.java        |   439 +
 .../server/web/servlets/RestletHttpServlet.java    |    55 +
 .../server/web/servlets/SearchHolderServlet.java   |   110 +
 .../server/web/servlets/SettingsServlet.java       |   423 +
 .../dicoogle/server/web/servlets/TagsServlet.java  |    78 +
 .../server/web/servlets/accounts/LoginServlet.java |   110 +
 .../web/servlets/accounts/LogoutServlet.java       |    55 +
 .../server/web/servlets/accounts/UserServlet.java  |    86 +
 .../web/servlets/management/AETitleServlet.java    |    68 +
 .../management/DicomQuerySettingsServlet.java      |   184 +
 .../web/servlets/management/ForceIndexing.java     |   155 +
 .../management/IndexerSettingsServlet.java         |   158 +
 .../web/servlets/management/LoggerServlet.java     |    90 +
 .../web/servlets/management/RemoveServlet.java     |    82 +
 .../servlets/management/RunningTasksServlet.java   |    71 +
 .../servlets/management/ServerStorageServlet.java  |   112 +
 .../web/servlets/management/ServicesServlet.java   |   198 +
 .../management/TransferOptionsServlet.java         |   124 +
 .../web/servlets/management/UnindexServlet.java    |    86 +
 .../server/web/servlets/search/DumpServlet.java    |   120 +
 .../server/web/servlets/search/ExportServlet.java  |   126 +
 .../web/servlets/search/ProvidersServlet.java      |    87 +
 .../server/web/servlets/search/SearchServlet.java  |   280 +
 .../server/web/servlets/search/WadoServlet.java    |    94 +
 .../web/servlets/webui/WebUIModuleServlet.java     |   112 +
 .../server/web/servlets/webui/WebUIServlet.java    |   131 +
 .../server/web/utils/DIM2JSONConverter.java        |   146 +
 .../ua/dicoogle/server/web/utils/ImageLoader.java  |   122 +
 .../dicoogle/server/web/utils/ImageRetriever.java  |    41 +
 .../dicoogle/server/web/utils/LocalImageCache.java |   301 +
 .../pt/ua/dicoogle/server/web/utils/Pages.java     |    42 +
 .../pt/ua/dicoogle/server/web/utils/Query.java     |    61 +
 .../ua/dicoogle/server/web/utils/ResponseUtil.java |    74 +
 .../server/web/utils/SimpleImageRetriever.java     |    75 +
 .../pt/ua/dicoogle/server/web/utils/TreeNode.java  |   174 +
 .../dicoogle/server/web/utils/types/DataTable.java |   306 +
 .../ua/dicoogle/taskManager/RunningIndexTasks.java |   120 +
 .../pt/ua/dicoogle/taskManager/TaskManager.java    |    57 +
 .../main/java/pt/ua/dicoogle/utils/CPULoad.java    |    88 +
 .../main/java/pt/ua/dicoogle/utils/Dicom2JPEG.java |   144 +
 .../java/pt/ua/dicoogle/utils/KeysManager.java     |   117 +
 dicoogle/src/main/resources/log4j2.xml             |    29 +
 dicoogle/src/main/resources/log4j2_sentry.xml      |    38 +
 dicoogle/src/main/resources/version.txt            |     1 +
 dicoogle/src/main/resources/webapp/.eslintrc       |    81 +
 dicoogle/src/main/resources/webapp/.gitignore      |     4 +
 dicoogle/src/main/resources/webapp/README.md       |    79 +
 .../main/resources/webapp/assets/drawer_menu.png   |   Bin 0 -> 13561 bytes
 .../src/main/resources/webapp/assets/favicon.ico   |   Bin 0 -> 11654 bytes
 .../resources/webapp/assets/image-not-found.png    |   Bin 0 -> 11563 bytes
 dicoogle/src/main/resources/webapp/assets/logo.png |   Bin 0 -> 127741 bytes
 .../resources/webapp/assets/logos/logo-ieeta.png   |   Bin 0 -> 4559 bytes
 .../main/resources/webapp/assets/logos/logo-ua.png |   Bin 0 -> 3329 bytes
 .../main/resources/webapp/assets/logos/logo.png    |   Bin 0 -> 3765 bytes
 .../main/resources/webapp/assets/logos/logoFCT.png |   Bin 0 -> 75459 bytes
 .../main/resources/webapp/assets/logos/logobio.png |   Bin 0 -> 11483 bytes
 .../_pgbackup/bootstrap-theme.min_1422916890.css   |     5 +
 .../_pgbackup/bootstrap-theme.min_1422917240.css   |     5 +
 .../_pgbackup/bootstrap-theme.min_1422917712.css   |     5 +
 .../_pgbackup/bootstrap-theme.min_1422917766.css   |     5 +
 .../css/_pgbackup/bootstrap_1422916890.css         |  6332 ++++++
 .../webapp/bootstrap/css/bootstrap-theme.css       |   470 +
 .../webapp/bootstrap/css/bootstrap-theme.min.css   |     5 +
 .../resources/webapp/bootstrap/css/bootstrap.css   |  6332 ++++++
 .../webapp/bootstrap/css/bootstrap.css.map         |     1 +
 .../webapp/bootstrap/css/bootstrap.min.css         |     5 +
 .../fonts/glyphicons-halflings-regular.eot         |   Bin 0 -> 20335 bytes
 .../fonts/glyphicons-halflings-regular.svg         |   229 +
 .../fonts/glyphicons-halflings-regular.ttf         |   Bin 0 -> 41280 bytes
 .../fonts/glyphicons-halflings-regular.woff        |   Bin 0 -> 23320 bytes
 .../resources/webapp/bootstrap/js/bootstrap.js     |  2320 +++
 .../resources/webapp/bootstrap/js/bootstrap.min.js |     7 +
 .../src/main/resources/webapp/css/font-awesome.css |  1801 ++
 .../main/resources/webapp/css/font-awesome.min.css |     4 +
 .../src/main/resources/webapp/css/fonts-google.css |     6 +
 .../css/images/ui-bg_flat_75_ffffff_40x100.png     |   Bin 0 -> 178 bytes
 .../src/main/resources/webapp/css/jquery-ui.css    |  1225 ++
 .../src/main/resources/webapp/css/loaders.min.css  |     1 +
 .../webapp/css/react-bootstrap-table.min.css       |     1 +
 .../main/resources/webapp/css/simple-sidebar.css   |   125 +
 dicoogle/src/main/resources/webapp/css/theme.css   |    75 +
 dicoogle/src/main/resources/webapp/filetest.json   |     1 +
 .../main/resources/webapp/fonts/FontAwesome.otf    |   Bin 0 -> 93888 bytes
 .../resources/webapp/fonts/fontawesome-webfont.eot |   Bin 0 -> 60767 bytes
 .../resources/webapp/fonts/fontawesome-webfont.svg |   565 +
 .../resources/webapp/fonts/fontawesome-webfont.ttf |   Bin 0 -> 122092 bytes
 .../webapp/fonts/fontawesome-webfont.woff          |   Bin 0 -> 71508 bytes
 .../webapp/fonts/fontawesome-webfont.woff2         |   Bin 0 -> 56780 bytes
 dicoogle/src/main/resources/webapp/gulpfile.js     |   161 +
 .../src/main/resources/webapp/index-template.html  |    71 +
 .../resources/webapp/js/actions/dumpActions.js     |     4 +
 .../resources/webapp/js/actions/exportActions.js   |     6 +
 .../webapp/js/actions/indexStatusAction.js         |     8 +
 .../resources/webapp/js/actions/indexerActions.js  |     5 +
 .../resources/webapp/js/actions/loggerActions.js   |     4 +
 .../webapp/js/actions/providersActions.js          |     4 +
 .../webapp/js/actions/resultSelectAction.js        |    13 +
 .../resources/webapp/js/actions/searchActions.js   |     7 +
 .../resources/webapp/js/actions/servicesAction.js  |    14 +
 .../resources/webapp/js/actions/storageActions.js  |     6 +
 .../resources/webapp/js/actions/transferActions.js |     7 +
 .../resources/webapp/js/actions/userActions.js     |     6 +
 .../resources/webapp/js/actions/versionAction.js   |     5 +
 dicoogle/src/main/resources/webapp/js/app.js       |   189 +
 .../webapp/js/components/about/aboutView.js        |    97 +
 .../webapp/js/components/direct/directDumpView.js  |    75 +
 .../webapp/js/components/direct/directImageView.js |    28 +
 .../js/components/indexer/IndexStatusView.js       |   106 +
 .../webapp/js/components/indexer/TaskStatus.jsx    |    84 +
 .../webapp/js/components/login/loadingView.js      |    60 +
 .../webapp/js/components/login/loginView.js        |   114 +
 .../webapp/js/components/management/indexerView.js |   137 +
 .../webapp/js/components/management/loggerView.js  |    56 +
 .../js/components/management/managementView.js     |    46 +
 .../js/components/management/queryadvoptions.js    |   141 +
 .../js/components/management/serviceForm.jsx       |   127 +
 .../js/components/management/servicesView.js       |   187 +
 .../webapp/js/components/management/storageView.js |   184 +
 .../components/management/transferOptionsView.js   |   138 +
 .../webapp/js/components/mixins/userMixin.js       |    20 +
 .../webapp/js/components/plugin/pluginForm.jsx     |    58 +
 .../webapp/js/components/plugin/pluginView.jsx     |    76 +
 .../webapp/js/components/search/advancedSearch.js  |   218 +
 .../webapp/js/components/search/exportView.js      |    51 +
 .../js/components/search/result/confirmModal.js    |    29 +
 .../js/components/search/result/imageView.js       |   372 +
 .../js/components/search/result/patientView.js     |   224 +
 .../js/components/search/result/serieView.js       |   224 +
 .../js/components/search/result/studyView.js       |   215 +
 .../webapp/js/components/search/searchResult.jsx   |   265 +
 .../js/components/search/searchResultView.jsx      |    83 +
 .../webapp/js/components/search/searchView.jsx     |   296 +
 .../main/resources/webapp/js/components/sidebar.js |    50 +
 .../webapp/js/constants/defaultOptions.js          |     4 +
 .../resources/webapp/js/constants/dimFields.js     |    34 +
 .../resources/webapp/js/constants/endpoints.js     |     5 +
 .../resources/webapp/js/handlers/requestHandler.js |   211 +
 .../main/resources/webapp/js/stores/dumpStore.js   |    40 +
 .../main/resources/webapp/js/stores/exportStore.js |    74 +
 .../resources/webapp/js/stores/indexStatusStore.js |    96 +
 .../resources/webapp/js/stores/indexerStore.js     |    41 +
 .../main/resources/webapp/js/stores/loggerStore.js |    42 +
 .../resources/webapp/js/stores/providersStore.js   |    46 +
 .../resources/webapp/js/stores/resultSelected.js   |    64 +
 .../main/resources/webapp/js/stores/searchStore.js |    89 +
 .../resources/webapp/js/stores/servicesStore.js    |   166 +
 .../resources/webapp/js/stores/storageStore.js     |    89 +
 .../resources/webapp/js/stores/transferStore.js    |    88 +
 .../main/resources/webapp/js/stores/userStore.js   |   151 +
 .../resources/webapp/js/stores/versionStore.js     |    37 +
 .../src/main/resources/webapp/js/utils/time.js     |    44 +
 dicoogle/src/main/resources/webapp/js/utils/url.js |    15 +
 dicoogle/src/main/resources/webapp/package.json    |   108 +
 dicoogle/src/main/resources/webapp/run_server      |     2 +
 .../resources/webapp/sass/components/_buttons.scss |    14 +
 .../resources/webapp/sass/components/_loaders.scss |     3 +
 .../resources/webapp/sass/components/_step.scss    |   252 +
 .../resources/webapp/sass/components/about.scss    |    16 +
 .../webapp/sass/components/advancedSearch.scss     |     8 +
 .../resources/webapp/sass/components/export.scss   |     4 +
 .../resources/webapp/sass/components/login.scss    |    68 +
 .../main/resources/webapp/sass/core/_colors.scss   |    14 +
 .../main/resources/webapp/sass/core/_dimens.scss   |     1 +
 .../main/resources/webapp/sass/core/_fonts.scss    |     1 +
 .../main/resources/webapp/sass/core/_global.scss   |    90 +
 .../main/resources/webapp/sass/core/_sections.scss |    17 +
 .../src/main/resources/webapp/sass/dicoogle.scss   |    18 +
 .../resources/webapp/sass/modules/_management.scss |    66 +
 .../resources/webapp/sass/modules/_sidebar.scss    |    29 +
 .../resources/webapp/sass/modules/_topbar.scss     |    38 +
 .../resources/webapp/sass/modules/_user-info.scss  |    13 +
 .../java/pt/ua/dicoogle/core/auth/TestRoles.java   |    67 +
 .../java/pt/ua/dicoogle/core/auth/TestUsers.java   |    74 +
 .../java/pt/ua/dicoogle/webui/CamelizeTest.java    |    62 +
 license.md                                         |   674 +
 pom.xml                                            |   127 +
 sdk-ext/.gitignore                                 |     2 +
 sdk-ext/pom.xml                                    |   163 +
 .../pt/ua/dicoogle/sdk/GenericPluginInterface.java |    72 +
 .../pt/ua/dicoogle/sdk/GraphicPluginAdapter.java   |    31 +
 .../pt/ua/dicoogle/sdk/NetworkPluginAdapter.java   |   212 +
 .../java/pt/ua/dicoogle/sdk/Utils/Platform.java    |    91 +
 .../java/pt/ua/dicoogle/sdk/Utils/PluginPanel.java |    34 +
 .../java/pt/ua/dicoogle/sdk/Utils/QueryNumber.java |    56 +
 .../java/pt/ua/dicoogle/sdk/Utils/TaskQueue.java   |    55 +
 .../java/pt/ua/dicoogle/sdk/Utils/TaskRequest.java |    86 +
 .../dicoogle/sdk/Utils/TaskRequestsConstants.java  |    50 +
 .../ua/dicoogle/sdk/index/DicomByteArrField.java   |    68 +
 .../pt/ua/dicoogle/sdk/index/DicomDocument.java    |    63 +
 .../ua/dicoogle/sdk/index/DicomNumericField.java   |    68 +
 .../pt/ua/dicoogle/sdk/index/DicomTextField.java   |    68 +
 .../java/pt/ua/dicoogle/sdk/index/IDicomField.java |    27 +
 .../main/java/pt/ua/dicoogle/sdk/index/IDoc.java   |    34 +
 .../dicoogle/sdk/index/IndexPluginInterface.java   |    44 +
 .../java/pt/ua/dicoogle/sdk/index/LongField.java   |    68 +
 .../sdk/index/handlers/DocumentHandler.java        |    31 +
 .../index/handlers/DocumentHandlerException.java   |    34 +
 .../sdk/index/handlers/ExtensionFileHandler.java   |    92 +
 .../index/handlers/FileAlreadyExistsException.java |    28 +
 .../sdk/index/handlers/FileHandlerException.java   |    38 +
 .../dicoogle/sdk/index/handlers/handler.properties |     1 +
 .../dicoogle/sdk/observables/FileObservable.java   |    66 +
 .../dicoogle/sdk/observables/ListObservable.java   |   107 +
 .../sdk/observables/ListObservableSearch.java      |    73 +
 .../sdk/observables/MessageObservable.java         |    75 +
 .../sdk/p2p/Messages/Builders/MessageBuilder.java  |   180 +
 .../ua/dicoogle/sdk/p2p/Messages/FileMessage.java  |    39 +
 .../p2p/Messages/Handlers/FileRequestHandler.java  |   158 +
 .../p2p/Messages/Handlers/FileResponseHandler.java |   132 +
 .../p2p/Messages/Handlers/MainMessageHandler.java  |    70 +
 .../sdk/p2p/Messages/Handlers/MessageHandler.java  |    36 +
 .../sdk/p2p/Messages/Handlers/QueryHandler.java    |   180 +
 .../Messages/Handlers/QueryResponseHandler.java    |   170 +
 .../dicoogle/sdk/p2p/Messages/MessageFields.java   |    61 +
 .../pt/ua/dicoogle/sdk/p2p/Messages/MessageI.java  |    33 +
 .../ua/dicoogle/sdk/p2p/Messages/MessageType.java  |    31 +
 .../ua/dicoogle/sdk/p2p/Messages/MessageXML.java   |    68 +
 .../ua/dicoogle/sdk/p2p/Messages/ObjMessage.java   |    46 +
 .../sdk/p2p/Messages/SearchResultFields.java       |    33 +
 sdk/.gitignore                                     |     2 +
 sdk/pom.xml                                        |   208 +
 .../java/pt/ua/dicoogle/sdk/DicooglePlugin.java    |    80 +
 .../pt/ua/dicoogle/sdk/GraphicalInterface.java     |    43 +
 .../java/pt/ua/dicoogle/sdk/IndexerInterface.java  |    72 +
 .../pt/ua/dicoogle/sdk/JettyPluginInterface.java   |    35 +
 .../main/java/pt/ua/dicoogle/sdk/PluginBase.java   |   109 +
 .../main/java/pt/ua/dicoogle/sdk/PluginSet.java    |   117 +
 .../java/pt/ua/dicoogle/sdk/QueryInterface.java    |    46 +
 .../pt/ua/dicoogle/sdk/StorageInputStream.java     |    52 +
 .../java/pt/ua/dicoogle/sdk/StorageInterface.java  |    91 +
 .../sdk/core/DicooglePlatformInterface.java        |   189 +
 .../sdk/core/PlatformCommunicatorInterface.java    |    36 +
 .../ua/dicoogle/sdk/core/ServerSettingsReader.java |   139 +
 .../pt/ua/dicoogle/sdk/core/WebSettingsReader.java |    33 +
 .../sdk/datastructs/DocumentIndexReport.java       |    96 +
 .../ua/dicoogle/sdk/datastructs/IndexReport.java   |    29 +
 .../ua/dicoogle/sdk/datastructs/IndexReport2.java  |    95 +
 .../pt/ua/dicoogle/sdk/datastructs/Measurable.java |    35 +
 .../dicoogle/sdk/datastructs/MoveDestination.java  |   145 +
 .../pt/ua/dicoogle/sdk/datastructs/Report.java     |    27 +
 .../ua/dicoogle/sdk/datastructs/SearchResult.java  |   163 +
 .../dicoogle/sdk/datastructs/TaskIndexReport.java  |    85 +
 .../pt/ua/dicoogle/sdk/factory/PluginFactory.java  |    46 +
 .../dicoogle/sdk/settings/ConfigurationHolder.java |    53 +
 .../pt/ua/dicoogle/sdk/settings/CoreSettings.java  |    53 +
 .../sdk/settings/InvalidSettingValueException.java |    48 +
 .../java/pt/ua/dicoogle/sdk/settings/Settings.java |   118 +
 .../java/pt/ua/dicoogle/sdk/settings/Utils.java    |   272 +
 .../sdk/settings/types/CheckboxWithHint.java       |   112 +
 .../ua/dicoogle/sdk/settings/types/ComboBox.java   |   128 +
 .../ua/dicoogle/sdk/settings/types/DataTable.java  |   337 +
 .../sdk/settings/types/GenericSetting.java         |    54 +
 .../dicoogle/sdk/settings/types/RangeInteger.java  |    97 +
 .../sdk/settings/types/ServerDirectoryPath.java    |    97 +
 .../sdk/settings/types/StaticDataTable.java        |   128 +
 .../pt/ua/dicoogle/sdk/task/JointQueryTask.java    |   104 +
 .../pt/ua/dicoogle/sdk/task/ProgressCallable.java  |    36 +
 .../main/java/pt/ua/dicoogle/sdk/task/Task.java    |    82 +
 .../pt/ua/dicoogle/sdk/utils/DictionaryAccess.java |   104 +
 .../java/pt/ua/dicoogle/sdk/utils/TagValue.java    |   197 +
 .../java/pt/ua/dicoogle/sdk/utils/TagsStruct.java  |   469 +
 .../pt/ua/dicoogle/sdk/utils/package-info.java     |     7 +
 .../dicoogle/sdk/utils/query/ForEachAdapter.java   |    39 +
 .../java/pt/ua/dicoogle/sdk/utils/query/Query.java |   160 +
 .../ua/dicoogle/sdk/utils/query/package-info.java  |     7 +
 short-license.txt                                  |    16 +
 webcore/.eslintrc                                  |    43 +
 webcore/README.md                                  |   226 +
 webcore/package.json                               |    40 +
 webcore/src/dicoogle-webcore.js                    |   567 +
 webcore/src/jsconfig.json                          |     6 +
 webcore/test/TC/document-register-element.js       |     2 +
 webcore/test/TC/react-0.13.0.js                    | 19535 ++++++++++++++++++
 webcore/test/TC/react-dropzone.js                  | 19804 +++++++++++++++++++
 webcore/test/TC/reactable.js                       |   955 +
 webcore/test/TC/require.js                         |  2083 ++
 webcore/test/TC/test-lazy-w-react.html             |    62 +
 webcore/test/TC/test-query-result-w-react.html     |    42 +
 webcore/test/TC/test-w-react.html                  |    40 +
 webcore/test/TC/test.html                          |    37 +
 webcore/test/dummy/dummy.js                        |    66 +
 webcore/test/dummy/package.json                    |    18 +
 webcore/test/react-todo/.babelrc                   |     3 +
 webcore/test/react-todo/module.js                  |    89 +
 webcore/test/react-todo/package.json               |    20 +
 webcore/test/react-todo/todo.jsx                   |    47 +
 webcore/test/simple-query/module.js                |    50 +
 webcore/test/simple-query/package.json             |    13 +
 webcore/test/simple-query/simple-query.js          |    50 +
 webcore/test/simple-result/Gruntfile.js            |    96 +
 webcore/test/simple-result/dep/reactable.js        |   955 +
 webcore/test/simple-result/module.js               |   926 +
 webcore/test/simple-result/module.js.map           |     1 +
 webcore/test/simple-result/module.min.js           |     1 +
 webcore/test/simple-result/package.json            |    29 +
 webcore/test/simple-result/simple-result.jsx       |    80 +
 .../simple-result/template/returnModuleExports.hbs |    18 +
 537 files changed, 138251 insertions(+), 68 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6371d0e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+node_modules/
+dist
+.tmp
+.sass-cache/
+app/bower_components
+
+#eclipse
+.project
+.settings/*
+dicoogle/.classpath
+dicoogle/.settings/*
+sdk-ext/.classpath
+sdk-ext/.settings/*
+sdk/.classpath
+sdk/.project
+sdk/.settings/*
+webcore/lib/
+.idea
+.vscode/
+*.iml
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..557eeb4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,198 @@
+<img src="https://cloud.githubusercontent.com/assets/4738426/21611123/64d0b4de-d1c3-11e6-8f99-d14fce8591f2.png" height="50"/>
+===================================================================
+
+Dicoogle is an extensible, platform-independent and open-source PACS archive software that replaces the traditional centralized database with a more agile indexing and retrieval mechanism. It was designed to support automatic extraction, indexing and storage of all meta-data detected in medical images, including private DICOM attribute tags, without re-engineering or reconfiguration requirements.
+
+The architecture of Dicoogle is described in the following article:
+
+Valente, F., Silva, L.A.B., Godinho, T.M., Costa, C. _Anatomy of an Extensible Open Source PACS_. J Digit Imaging (2016) 29: 284. doi:10.1007/s10278-015-9834-0 [Available Online: http://link.springer.com/article/10.1007/s10278-015-9834-0]
+
+Our official website is at www.dicoogle.com. A few essential plugins for Dicoogle are available to download there, as well as a built jar of the Dicoogle platform. To build the core platform yourself, please see the section on [Building Dicoogle](#building-dicoogle).
+
+Brief Documentation
+-------------------
+
+#### Setup Dicoogle Platform Environment
+  1. Copy dicoogle.jar to the installation folder. For example DicoogleDir/
+  2. Create the Folder DicoogleDir/Plugins.
+
+      This folder will hold the plugins used by our instance of the Dicoogle Platform.
+  3. Next, copy the desired plugins into the DicoogleDir/Plugins Folder.
+      
+      The typical setup of Dicoogle involves the deployment of an Indexing and Query Plugin. 
+      We supply an implementation of such plugin based in Apache Lucene. 
+  4. Run Dicoogle.
+  
+      Dicoogle may be run as a server: ```java -jar dicoogle.jar -s```
+
+      To load the server and open Dicoogle's user interface with the default browser: ```java -jar dicoogle.jar```
+
+#### Available Plugins
+  
+  We provide a few plugins at the official website, in the [Downloads](http://www.dicoogle.com/?page_id=67) page.
+
+  * Lucene Index/Query Plugin - (lucene.jar)
+      
+      Plugin Based on Apache Lucene to support indexing and querying of DICOM meta-data. With this plugin set, it is possible to index nearly meta-data and perform free text, keyword-based, and range-based queries.
+      
+  * File Storage Plugin - (filestorage.jar)
+
+      Plugin used for the storage of DICOM Files. This plugin is necessary in order to use Dicoogle as a complete DICOM Storage Provider. The core platform provides a fallback implementation which supports reading (but not storing) files from the local file system.
+      
+      For storage purposes, our file storage plugin maps the DICOM hierarchical organization (Patient->Study->Series->Image) into a directory tree in the file system. Every object in the Dicoogle Platform may be traced back to its storage location by a URI, similar to file:/tmp/file. In order to support multiple providers, every Storage plugin must define a unique scheme, which maps to the protocol used to store and retrieve content. 
+      
+      * Settings
+      
+        * `root-dir`: is the root directory where DICOM Files will be stored
+        * `scheme`: Specifies the scheme/protocol of the file plugin. This value is arbitrary, but must be unique among all installed plugins. As such, avoid using well known protocol names such as http or file.
+
+  * Dicoogle Wan Plugin - (wan-plugin.jar)
+
+      The WAN Plugin may be used to federate instances of the Dicoogle Repository. The google app engine is used to federate and relay communications between the multiple instances.
+      It is possible to call services on remote instances of the Dicoogle Platform seamlessly, such as, Query or Retrieval of studies.
+
+#### Configuring Plugins
+
+  Plugin configurations are accessible via "/DicoogleDir/Plugins/settings/_PluginName_.xml", where _PluginName_ stands for the name of the plugin.
+  Upon initialization, if no configurations file is supplied, a new one with the default values is created.
+
+#### Using the Web Application
+
+  * Configuring Services
+
+      In the Management Page, Services and Plugins settings, it is possible to start and/or stop currently running services in real time. Moreover, some configurations like the DICOM service ports may be set.
+
+  * Index a Directory
+
+      Indexing a directory is done simply by accessing the Indexer page, on the side bar. 
+      In this page, one can select a root directory to index. The path is a URI defined according to the storage provider, and defaults to the `file` scheme.
+      
+      In the Management pange, one may also enable the Dicoogle Directory Watcher, which creates a daemon that listens for new files in the root directory.
+      After selecting the configurations, the "Apply Settings" button must be pressed.
+      When the right settings are saved, the Start buttons fires the indexing process. Please note that this process may take considerable time to complete.
+
+  * Using the Search Interface
+
+      The search page enables users to execute queries over the indexed meta-data.
+      The query syntax is similar to the Lucene's Tag:Value query format, but free text searches are also supported. For inexperienced users, an advanced input module may also be used.
+      
+      In the search interface, it is also possible to select which providers to query. Query providers are actually Query Plugins, that are installed either in the local instance of Dicoogle, or in remote instances if the platform is using the WAN plugin. Therefore, be careful and select exactly which providers you want to query, in order to retrieve more accurate and faster results.
+
+  * Export Results 
+
+      After running a query, the result browser shows up, giving the user an intuitive hierarchical view of the results. On this page, there is also an Export button, which is used in order to export the query results into a CSV file. When the export button is clicked, the user has to select which tags (s)he wants to export in the CSV file. This selection is heavily assisted by the interface, on which the user may type an incomplete tag and have presented the available candidates that ma [...]
+
+#### Using the Web Services
+
+  Let us assume that the Web Services for our instance of Dicoogle are running in http://demo.dicoogle.com/
+ 
+  * Searching
+     Dicoogle provides a flexible web service for querying, under the `/search` endpoint.
+  
+    * Search by Date Range, Access images in date 2005/03/29
+
+       Query: `"StudyDate:[20050329 TO 20050329]"`
+       
+       URL: `http://demo.dicoogle.com/search?query=StudyDate:[20050329%20TO%2020050329]`
+    
+    * Access images in date 2005/03/29 and CT (Computer Tomography) modality
+        
+       Query: `"Modality:CT AND StudyDate:[20050329 TO 20050329]"`
+       
+       URL: `http://demo.dicoogle.com/search?query=Modality:CT%20AND%20StudyDate:[20050329%20TO%2020050329]`
+
+    * Free text search, looking for CT keyword
+
+       Query: `CT`
+       
+       URL: `http://demo.dicoogle.com/search?query=CT`
+
+  * Access the list of attributes of an image (by SOPInstanceUID)
+
+     URL: `http://demo.dicoogle.com/dump?uid=1.3.12.2.1107.5.1.4.54023.30000005032914013107800000965`
+  
+  * Get a DICOM File
+
+     URL: `http://demo.dicoogle.com/legacy/file?uid=1.3.12.2.1107.5.1.4.54023.30000005032914013107800000965`
+
+  * Return documents from particular query providers (useful for queries that do not follow the typical Lucene query format)
+  
+    URL: `http://demo.dicoogle.com/search?query=Modality:NM&provider=lucene&provider=mongo`
+    
+    Parameters:
+      - query : Query String
+      - provider: name of the query providers - multiple - optional
+         - all: default - asks all available providers.
+         - _provider name_: name of the provider, e.g. `lucene`.
+
+  * Force Dicoogle to index a given Resource. (useful when conventional notification systems (DICOM Services, DirectoryMonitoring, Human Interface) fail to start the index procedure)
+
+    URL: `http://demo.dicoogle.com/management/tasks/index?uri=file:/tmp/dataset-ieeta/`
+    
+    - Method: `POST`
+    - Parameters:
+      - uri: The root identifier of the resources that will be indexed. Please note that Dicoogle will fetch these resources from a storage plugin. Therefore, a plugin capable of handling these resources must be enabled. The provider is identified by the URI's scheme.
+
+A live demo was deployed at the given URL. Feel free to experiment with these services.
+
+We also have programmatic APIs for interfacing with Dicoogle in [JavaScript](https://github.com/bioinformatics-ua/dicoogle-client-js), [Java](https://github.com/bioinformatics-ua/dicoogle-java), and [Python](https://github.com/bioinformatics-ua/dicoogle-python).
+
+#### Create your own Plugins
+
+  In order to integrate new functionalities in Dicoogle, you may create your own plugin set. A plugin set comprises plugins that are developed with the intent of supporting a given feature, and are packaged in a single jar file for deployment. See the wiki page on [Plugin Development](https://github.com/bioinformatics-ua/dicoogle/wiki/Plugin-Development) for our guide, and our [sample plugin project](https://github.com/bioinformatics-ua/dicoogle-plugin-sample) for a base project from whi [...]
+
+### Building Dicoogle 
+
+Before building, please make sure that your system contains the following tools:
+
+ - Java JDK, either Oracle or OpenJDK (at least version 7; JDK 8 is recommended)
+ - Maven 3
+ - [Node.js](https://nodejs.org/en/download/) (at least version 4; LTS or Stable versions are recommended) and npm (at least version 2)
+
+ 1. Retrieve the full source code from this repository: `git clone https://github.com/bioinformatics-ua/dicoogle.git`
+ 2. Navigate to the project's base directory, and build the parent Maven project by calling `mvn install`.
+    - Note: if you want, you can skip the npm part: `mvn install -Dskip.npm`
+ 3. The resulting jar file can be found in "./dicoogle/target".
+
+
+Contributing
+------------
+
+The open source project is maintained by [UA.PT Bioinformatics](http://bioinformatics.ua.pt/) and [BMD Software](https://www.bmd-software.com/). Your contributions to the software are also welcome. Dicoogle is sought to be useful for R&D and the industry alike. You may find our [Development Guidelines](https://github.com/bioinformatics-ua/dicoogle/wiki#development-guidelines) in the wiki. Issues containing the [`easy`](https://github.com/bioinformatics-ua/dicoogle/issues?q=is%3Aissue+is% [...]
+
+
+## Support and consulting
+[<img src="https://raw.githubusercontent.com/wiki/BMDSoftware/dicoogle/images/bmd.png" height="64" alt="BMD Software">](https://www.bmd-software.com)
+
+Please contact [BMD Software](https://www.bmd-software.com) for professional support and consulting services.
+
+
+Project committers
+------------------
+
+Maintainers:
+
+* Luís Bastião (BMD software - development leader) - [@bastiao](https://github.com/bastiao)
+* Eduardo Pinho (UA.PT Bioinformatics) - [@Enet4](https://github.com/Enet4)
+
+Contributors:
+
+* Renato Pinho (BMD software)
+* David Campos (BMD software)
+* Eriksson Monteiro (UA.PT Bioinformatics)
+* Tiago Godinho (UA.PT Bioinformatics)
+* Jorge Miguel Silva (UA.PT Bioinformatics)
+
+Past developers:
+
+* Samuel Campos
+* Carlos Ferreira
+* Luis Ribeiro
+* Frederico Valente
+
+Project leaders
+---------------
+
+* Carlos Costa and José Luis Oliveira (UA.PT Bioinformatics, scientific advisors)
+* Luís Bastião (BMD software - development)
+
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index de113d0..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-dicoogle (2.5.0-1) UNRELEASED; urgency=low
-
-  * Initial Debian Upload (Closes: #)
-
- -- Mathieu Malaterre <mathieu.malaterre at gmail.com>  Mon, 12 Sep 2011 09:56:16 +0200
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 805d6be..0000000
--- a/debian/control
+++ /dev/null
@@ -1,24 +0,0 @@
-Source: dicoogle
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Mathieu Malaterre <mathieu.malaterre at gmail.com>
-Section: java
-Priority: optional
-Build-Depends: debhelper (>= 10),
-               javahelper
-Build-Depends-Indep: default-jdk,
-                     default-jdk-doc,
-                     ant
-Standards-Version: 3.9.8
-Vcs-Browser: http://anonscm.debian.org/viewvc/debian-med/trunk/packages/dicoogle/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/dicoogle/trunk/
-Homepage: http://dicoogle.com
-
-Package: dicoogle
-Architecture: any
-Depends: ${java:Depends},
-         ${misc:Depends}
-Recommends: ${java:Recommends}
-Description: Java Advanced Imaging API reference implementation
- This project contains the source code for the core Java Advanced Imaging API
- reference implementation containing the packages javax.media.jai.* and
- com.sun.media.jai.*.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 6ee7dd6..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,25 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: Dicoogle
-Source: https://github.com/bioinformatics-ua/dicoogle/releases
-
-Files: *
-Copyright: © 2010 IEETA
-Licence: GPL-3
-  Dicoogle is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License as published by
-  the Free Software Foundation, either version 3 of the License, or
-  (at your option) any later version.
-
-  Dicoogle is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-  You should have received a copy of the GNU General Public License
-  along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
-
-
-Files: debian/*
-Copyright: © 2011 Mathieu Malaterre <mathieu.malaterre at gmail.com>
-License: PD
- The packaging work is in the public domain unless stated otherwise.
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 7cecc72..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/make -f
-
-JAVA_HOME=/usr/lib/jvm/default-java
-
-%:
-	dh $@ --with javahelper
-
-override_dh_auto_build:
-	ant -DBUILD_TYPE=fcs -f build.xml all
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index d8a095f..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,3 +0,0 @@
-version=4
-
-https://github.com/bioinformatics-ua/dicoogle/releases .*/archive/@ANY_VERSION@@ARCHIVE_EXT@
diff --git a/dicoogle/.gitignore b/dicoogle/.gitignore
new file mode 100644
index 0000000..e73c12f
--- /dev/null
+++ b/dicoogle/.gitignore
@@ -0,0 +1,22 @@
+/target
+/index
+/Plugins
+/clientConfig.xml
+/config.xml
+/nbactions.xml
+/DICOMLOG.log
+/foreignNames.ser
+/luceneplugin.log
+/luceneplugin.log.1
+/luceneplugin.log.1.lck
+/luceneplugin.log.lck
+/match.ser
+/QueryHistory.ser
+/sessions.log
+/tags.xml
+/users.xml
+/log4j-2.xml
+/log4j.properties
+/Server_Keystore
+/dependency-reduced-pom.xml
+*.log
diff --git a/dicoogle/pom.xml b/dicoogle/pom.xml
new file mode 100644
index 0000000..df5c891
--- /dev/null
+++ b/dicoogle/pom.xml
@@ -0,0 +1,388 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dicoogle</artifactId>
+    <packaging>jar</packaging>
+    <name>dicoogle</name>
+    <url>http://www.dicoogle.com</url>
+    
+    <parent>
+        <groupId>pt.ua.ieeta</groupId>
+        <artifactId>dicoogle-all</artifactId>
+        <version>2.5.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <log4j.version>2.2</log4j.version>
+
+        <maven.build.timestamp.format>yyyyMMdd_HHmm</maven.build.timestamp.format>
+        <buildNumber>${maven.build.timestamp}</buildNumber>
+    </properties>
+
+    <repositories>
+        <repository>
+            <id>mavencentral</id>
+            <url>http://repo1.maven.org/maven2/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>dcm4che</id>
+            <url>http://www.dcm4che.org/maven2/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+
+        <repository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+
+        <repository>
+            <id>mi-snapshots</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi-snapshots</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+
+        <repository>
+            <id>sourceforge-releases</id>
+            <name>Sourceforge Releases</name>
+            <url>https://oss.sonatype.org/content/repositories/sourceforge-releases</url>
+        </repository>
+
+        <repository>
+            <id>maven-restlet</id>
+            <name>Public online Restlet repository</name>
+            <url>http://maven.restlet.org</url>
+        </repository>
+
+    </repositories>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+
+        <resources>
+            <resource>
+                <directory>src/main/java/pt/ua/dicoogle/config</directory>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>log4j2.xml</include>
+                    <include>webapp/assets/**</include>
+                    <include>webapp/bootstrap/css/*.css</include>
+                    <include>webapp/bootstrap/fonts/*</include>
+                    <include>webapp/fonts/**</include>
+                    <include>webapp/css/**</include>
+                    <include>webapp/lib/**</include>
+                    <include>webapp/index.html</include>
+                </includes>
+                <excludes>
+                    <exclude>META-INF/*.SF</exclude>
+                    <exclude>META-INF/*.DSA</exclude>
+                    <exclude>META-INF/*.RSA</exclude>
+                </excludes>
+            </resource>
+           <resource>
+               <directory>src/main/resources</directory>
+               <filtering>true</filtering>
+               <includes>
+                   <include>version.txt</include>
+               </includes>
+            </resource>
+         </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <transformers>
+                                <transformer
+                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>pt.ua.dicoogle.Main</mainClass>
+                                    <manifestEntries>
+					    <Specification-Version>${project.version}</Specification-Version>
+					    <Implementation-Version>${project.version}</Implementation-Version>
+                                        <Extension-Name>com.sun.media.imageio</Extension-Name>
+                                        <Implementation-Vendor>BMD software/UA.PT Bioinformatics</Implementation-Vendor>
+                                        <Specification-Vendor>BMD software/UA.PT Bioinformatics</Specification-Vendor>
+                                        <Class-Path>./src/main/resources/</Class-Path>
+                                        <Sealed>true</Sealed>
+                                    </manifestEntries>
+                                </transformer>
+                            </transformers>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>**/*.SF</exclude>
+                                        <exclude>**/*.DSA</exclude>
+                                        <exclude>**/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                    <showDeprecation>true</showDeprecation>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.7</version>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/src/main/resources</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>${basedir}/target/version.txt</directory>
+                                    <includes>
+                                        <include>version.txt</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>com.mycila</groupId>
+                <artifactId>license-maven-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <header>../short-license.txt</header>
+                    <includes>
+                        <include>**/*.java</include>
+                    </includes>
+                    <excludes>
+                        <exclude>**/package-info.java</exclude>
+                    </excludes>
+
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- Webapp -->
+
+            <plugin>
+                <groupId>com.github.eirslett</groupId>
+                <artifactId>frontend-maven-plugin</artifactId>
+                <executions>
+                    <!-- Install Node and NPM -->
+                    <execution>
+                        <id>install node and npm</id>
+                        <goals>
+                            <goal>install-node-and-npm</goal>
+                        </goals>
+                        <phase>generate-resources</phase>
+                    </execution>
+                    <!-- install dependencies and build for webapp for production-->
+                    <execution>
+                        <id>npm install</id>
+                        <goals>
+                            <goal>npm</goal>
+                        </goals>
+
+                        <phase>generate-resources</phase>
+
+                        <configuration>
+                            <arguments>install</arguments>
+                        </configuration>
+                    </execution>
+
+                </executions>
+                <configuration>
+                    <nodeVersion>v6.9.1</nodeVersion>
+                    <npmVersion>3.10.10</npmVersion>
+                    <installDirectory>target</installDirectory>
+                    <!-- Defining webapp directory -->
+                    <workingDirectory>src/main/resources/webapp</workingDirectory>
+                </configuration>
+            </plugin>
+          
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>jaidcm4che</groupId>
+            <artifactId>jai_imageio</artifactId>
+            <version>1.1</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>jai_core</artifactId>
+                    <groupId>javax.media</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.1</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sf.json-lib</groupId>
+            <artifactId>json-lib</artifactId>
+            <classifier>jdk15</classifier>
+            <version>2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>dcm4che</groupId>
+            <artifactId>dcm4che-imageio</artifactId>
+            <version>${dcm4che.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.dicoogle.aclmanager</groupId>
+            <artifactId>aclmanager</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>pt.ua.ieeta</groupId>
+            <artifactId>dicoogle-sdk</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>pt.ua.ieeta</groupId>
+            <artifactId>dicoogle-sdk-ext</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.java.net.substance</groupId>
+            <artifactId>substance</artifactId>
+            <version>5.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-webapp</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlets</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-jsp</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.restlet.jee</groupId>
+            <artifactId>org.restlet.ext.servlet</artifactId>
+            <version>${restlet.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.8</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jdom</groupId>
+            <artifactId>jdom2</artifactId>
+            <version>2.0.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>19.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>metal.utils</groupId>
+            <artifactId>metal.utils.fileiterator</artifactId>
+            <version>1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>net.kencochrane.raven</groupId>
+            <artifactId>raven-log4j2</artifactId>
+            <version>5.0.2</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogDICOM.java b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogDICOM.java
new file mode 100755
index 0000000..2d3e229
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogDICOM.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.DicomLog;
+
+import java.util.ArrayList;
+import org.slf4j.LoggerFactory;
+import javax.xml.transform.TransformerConfigurationException;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class LogDICOM{
+
+    private static LogDICOM instance = null ;
+
+    private ArrayList<LogLine> ll = new ArrayList<LogLine>(); 
+
+    private LogDICOM()
+    {
+        // Nothing to do.
+    }
+
+
+    public static synchronized LogDICOM getInstance()
+    {
+        if (instance == null) {
+            instance = new LogDICOM();
+        }
+        return instance;
+    }
+
+
+    public void addLine(LogLine l)
+    {
+        this.getLl().add(l);
+    }
+
+    public void clearLog(){
+        this.getLl().clear();
+        
+        try {
+            LogXML log = new LogXML();
+            log.printXML();
+        } catch (TransformerConfigurationException ex) {
+            LoggerFactory.getLogger(LogDICOM.class.getName()).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * @return the ll
+     */
+    public ArrayList<LogLine> getLl()
+    {
+        return ll;
+    }
+
+    /**
+     * @param ll the ll to set
+     */
+    public void setLl(ArrayList<LogLine> ll)
+    {
+        this.ll = ll;
+    }
+
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogLine.java b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogLine.java
new file mode 100755
index 0000000..5da09e3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogLine.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package pt.ua.dicoogle.DicomLog;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class LogLine implements Serializable
+{
+    static final long serialVersionUID = 1L;
+
+    private String type;
+    private String date;
+    private String ae;
+    private String add;
+    private String params;
+
+    public LogLine(String type, String date, String ae, String add, String params)
+    {
+        this.type = type ; 
+        this.date = date ; 
+        this.ae = ae ; 
+        this.add = add ;
+        this.params = params;
+    }
+
+     public static String getDateTime() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        Date date = new Date();
+        return dateFormat.format(date);
+    }
+
+
+
+    /**
+     * @return the type
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+    /**
+     * @param type the type to set
+     */
+    public void setType(String type)
+    {
+        this.type = type;
+    }
+
+    /**
+     * @return the date
+     */
+    public String getDate()
+    {
+        return date;
+    }
+
+    /**
+     * @param date the date to set
+     */
+    public void setDate(String date)
+    {
+        this.date = date;
+    }
+
+    /**
+     * @return the ae
+     */
+    public String getAe()
+    {
+        return ae;
+    }
+
+    /**
+     * @param ae the ae to set
+     */
+    public void setAe(String ae)
+    {
+        this.ae = ae;
+    }
+
+    /**
+     * @return the add
+     */
+    public String getAdd()
+    {
+        return add;
+    }
+
+    /**
+     * @param add the add to set
+     */
+    public void setAdd(String add)
+    {
+        this.add = add;
+    }
+
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogXML.java b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogXML.java
new file mode 100755
index 0000000..0a5c86f
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/DicomLog/LogXML.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package pt.ua.dicoogle.DicomLog;
+
+import java.io.*;
+// SAX classes.
+
+//JAXP 
+import javax.xml.transform.*;
+import javax.xml.transform.stream.*;
+import javax.xml.transform.sax.*;
+
+
+import java.util.ArrayList;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.*;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class LogXML extends DefaultHandler
+{
+
+    //private final String filename = Platform.homePath() + "DICOM_Services_Log.xml";
+    private final String filename = "./DICOM_Services_Log.xml";
+
+    private LogDICOM logs = null;
+    private boolean logOn = false;
+    private String type = "";
+    private String date = "";
+    private String ae = "";
+    private String add = "";
+    private String params = "";
+
+    public LogXML()
+    {
+        logs = LogDICOM.getInstance();
+
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName,
+            Attributes attr)
+    {
+        if (localName.equals("log"))
+        {
+            this.logOn = true;
+        } else if (this.logOn && !localName.equals(""))
+        {
+            //...
+            this.type = localName;
+            this.ae = this.resolveAttrib("ae", attr, localName);
+            this.date = this.resolveAttrib("date", attr, localName);
+            this.add = this.resolveAttrib("add", attr, localName);
+        }
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName)
+    {
+
+        if (localName.equals("log"))
+        {
+            this.logOn = false;
+        } else if (!localName.equals(""))
+        {
+            logs.addLine(new LogLine(type, date, ae, add, params));
+        }
+    }
+
+    private String resolveAttrib(String attr, Attributes attribs, String defaultValue)
+    {
+        String tmp = attribs.getValue(attr);
+        return (tmp != null) ? (tmp) : (defaultValue);
+    }
+
+    public LogDICOM getXML()
+    {
+        try
+        {
+            File file = new File(filename);
+            if (!file.exists())
+            {
+
+                return logs;
+            }
+
+            InputSource src = new InputSource(new FileInputStream(file));
+            XMLReader r = null;
+            try
+            {
+                r = XMLReaderFactory.createXMLReader();
+            } catch (SAXException ex)
+            {
+            }
+            r.setContentHandler(this);
+            r.parse(src);
+            return logs;
+        } catch (IOException ex)
+        {
+        } catch (SAXException ex)
+        {
+        }
+        return null;
+    }
+
+    public void printXML() throws TransformerConfigurationException
+    {
+
+
+        FileOutputStream out = null;
+
+        try
+        {
+            out = new FileOutputStream(filename);
+            PrintWriter pw = new PrintWriter(out);
+            StreamResult streamResult = new StreamResult(pw);
+            SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+            //      SAX2.0 ContentHandler.
+            TransformerHandler hd = tf.newTransformerHandler();
+            Transformer serializer = hd.getTransformer();
+            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+            serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");
+            hd.setResult(streamResult);
+            hd.startDocument();
+
+            //Get a processing instruction
+            //hd.processingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"mystyle.xsl\"");
+            AttributesImpl atts = new AttributesImpl();
+
+
+            //root element
+            hd.startElement("", "", "log", atts);
+
+            ArrayList<LogLine> list = logs.getLl();
+            atts.clear();
+            for (LogLine l : list)
+            {
+                atts.addAttribute("", "", "date", "", l.getDate());
+                atts.addAttribute("", "", "ae", "", l.getAe());
+                atts.addAttribute("", "", "add", "", l.getAdd());
+                atts.addAttribute("","","params","",l.getParams());
+
+                hd.startElement("", "", l.getType(), atts);
+                atts.clear();
+
+                hd.endElement("", "", l.getType());
+
+            }
+            hd.endElement("", "", "log");
+
+            hd.endDocument();
+
+        } catch (TransformerConfigurationException ex)
+        {
+        } catch (SAXException ex)
+        {
+        } catch (FileNotFoundException ex)
+        {
+        } finally
+        {
+            try
+            {
+                out.close();
+            } catch (IOException ex)
+            {
+            }
+        }
+
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/ExceptionHandler.java b/dicoogle/src/main/java/pt/ua/dicoogle/ExceptionHandler.java
new file mode 100755
index 0000000..f03ed93
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/ExceptionHandler.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import javax.swing.JOptionPane;
+
+//import pt.ieeta.anonymouspatientdata.core.Anonymous;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+class ExceptionHandler implements Thread.UncaughtExceptionHandler {
+
+  public static String getStackTrace(Throwable throwable)
+  {
+    Writer writer = new StringWriter();
+    PrintWriter printWriter = new PrintWriter(writer);
+    throwable.printStackTrace(printWriter);
+    return writer.toString();
+  }
+
+
+  public void uncaughtException(Thread t, Throwable e) {
+    handle(e);
+  }
+
+  public void handle(Throwable throwable) {
+    try {
+        /**
+         * Here you can insert code to send exception to email etc.
+         */
+        if (/*DebugManager.getInstance().isDebug()*/true) {
+            throwable.printStackTrace();
+        } else {
+            String msg = getStackTrace(throwable);
+            if (msg.contains("heap"))
+            {
+                JOptionPane.showMessageDialog(null, "Generic Error, see log.txt.\n\nError: lack of memory. You should increase memory \n",
+                    "Exception Error", JOptionPane.INFORMATION_MESSAGE);
+            }
+            else
+            {    
+                 JOptionPane.showMessageDialog(null, "Generic Error, see log.txt.\n\nError: \n" + msg,
+                    "Exception Error", JOptionPane.INFORMATION_MESSAGE);
+            }
+            //DebugManager.getInstance().log(getStackTrace(throwable)+"\n");
+            System.err.println(getStackTrace(throwable)+"\n");
+        }
+      } catch (Throwable t) {
+      // don't let the exception get thrown out, will cause infinite looping!
+    }
+  }
+
+  public static void registerExceptionHandler() {
+    Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
+    System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
+  }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/LICENSE b/dicoogle/src/main/java/pt/ua/dicoogle/LICENSE
new file mode 100755
index 0000000..94a9ed0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/LICENSE
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/Main.java b/dicoogle/src/main/java/pt/ua/dicoogle/Main.java
new file mode 100755
index 0000000..63c5129
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/Main.java
@@ -0,0 +1,367 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle;
+
+import org.dcm4che2.data.TransferSyntax;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+import pt.ua.dicoogle.DicomLog.LogDICOM;
+import pt.ua.dicoogle.DicomLog.LogXML;
+import pt.ua.dicoogle.core.*;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.client.windows.ConnectWindow;
+import pt.ua.dicoogle.sdk.Utils.Platform;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.*;
+
+/**
+ * Main class for Dicoogle
+ * @author Filipe Freitas
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class Main
+{
+    private static final Logger logger = LoggerFactory.getLogger(Main.class);
+
+    private static boolean optimizeMemory = true;
+    private static boolean isGUIServer = false;
+    //indicates whether the client and the server were pulled at the same time
+    private static boolean isFixedClient = false;
+    private static int remoteGUIPort = 0;
+    public static boolean MAC_OS_X = (System.getProperty("os.name").toLowerCase().startsWith("mac os x"));
+    /**
+     * Generate a random integer number between 0 and 100
+     *
+     * This is used to verify if the RMI client is in the same
+     * process as the RMI server.
+     * The client as 1/1000 probability to hit the correct number
+     * if it is not in the same process.
+     */
+    public static int randomInteger = (new Random()).nextInt(1001);
+
+    /**
+     * Starts the graphical user interface for Dicoogle
+     * @param args the command line arguments
+     */
+    public static void main(String[] args)
+    {
+    	//System.setProperty("log4j.configurationFile", "log4j-2.xml");
+        //PropertyConfigurator.configure("log4j.properties");
+        if (Platform.getMode() == Platform.MODE.BUNDLE)
+        {
+            File homeDir = new File(Platform.homePath());
+            if (!homeDir.exists())
+            {
+                homeDir.mkdir();
+            }
+        }
+        
+        if (args.length == 0)
+        {
+            isFixedClient = true;
+
+            LaunchDicoogle();
+            LaunchWebApplication();
+        } else {
+
+            if (args[0].equals("-v"))
+            {
+                isFixedClient = true;
+                //DebugManager.getInstance().setDebug(true);
+                LaunchDicoogle();
+                //DebugManager.getInstance().debug("Starting Client Thread");
+                LaunchWebApplication();
+            }
+            if (args[0].equals("-s"))
+            {
+                LaunchDicoogle();
+            } else if (args[0].equals("-g") || args[0].equals("--gui"))
+            {
+                LaunchDicoogle();
+                LaunchGUIClient();
+            } else if (args[0].equals("-c"))
+            {
+                LaunchGUIClient();
+            }
+            else if (args[0].equals("-w") || args[0].equals("--web") || args[0].equals("--webapp")) {
+                // open browser
+                LaunchDicoogle();
+                LaunchWebApplication();
+            }
+            else if (args[0].equals("-h") || args[0].equals("--h") || args[0].equals("-help") || args[0].equals("--help"))
+            {
+                System.out.println("Dicoogle PACS: help");
+                System.out.println("-s : Start the server");
+                System.out.println("-w : Start the server and load web application in default browser (default)");
+                System.out.println("-g : [deprecated] Start the server and run the desktop client application");
+                System.out.println("-c : [deprecated] Run the desktop client application");
+            }
+            else
+            {
+                System.out.println("Wrong arguments!");
+            }
+        }
+        /** Register System Exceptions Hook */
+        ExceptionHandler.registerExceptionHandler();
+
+        optimizeMemoryUsage();
+    }
+
+    /**
+     * This function creates a TimerTask to periodically run Garbage Colector
+     *
+     */
+    private static void optimizeMemoryUsage()
+    {
+        if (optimizeMemory)
+        {
+            class FreeMemoryTask extends TimerTask
+            {
+
+                @Override
+                public void run()
+                {
+                    Runtime.getRuntime().gc();
+                    System.out.println("\nFree Memory: " + Runtime.getRuntime().freeMemory() / 1024 / 1024
+                            + "\nTotal Memory: " + Runtime.getRuntime().totalMemory() / 1024 / 1024
+                            + "\nMax Memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024);
+                }
+            }
+
+            //FreeMemoryTask freeMemTask = new FreeMemoryTask();
+            //Timer timer = new Timer();
+            //timer.schedule(freeMemTask, 5000, 5000);
+        }
+    }
+    
+    public static boolean LaunchWebApplication() {
+        if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
+            logger.warn("Desktop browsing is not supported in this machine! "
+                    + "Request to open web application ignored.");
+            return false;
+        } else {
+            try {
+                ServerSettings settings = ServerSettings.getInstance();
+                URI uri = URI.create("http://localhost:" + settings.getWeb().getServerPort());
+                Desktop.getDesktop().browse(uri);
+                return true;
+            } catch (IOException ex) {
+                logger.warn("Request to open web application ignored", ex);
+                return false;
+            }
+        }
+    }
+
+    public static void LaunchDicoogle()
+    {
+        try
+        {
+            //System.out.println("\n"+addressString(localAddresses()) + "\n");
+            System.setProperty("java.rmi.server.hostname", addressString(localAddresses()));
+        } catch (SocketException ex) {
+            logger.warn(ex.getMessage(), ex);
+        }
+        
+        logger.debug("Starting Dicoogle");
+        /* This logic will be not neccessary. This should be sent to the Plugins.
+        try
+        {
+            Anonymous.getInstance().start();
+        } catch(Exception e) {
+            logger.warn("Could not start Anonimize service", e);
+        }*/
+        
+        
+        logger.debug("Loading configuration file: {}", Platform.homePath());
+        
+        /* Load all Server Settings from XML */
+        ServerSettings settings = new XMLSupport().getXML();
+
+        try
+        {
+            TagsStruct _tags = new TagsXML().getXML();
+
+            //load DICOM Services Log
+            LogDICOM ll = new LogXML().getXML();
+
+        } catch (SAXException | IOException ex) {
+            logger.error(ex.getMessage(), ex);
+        }
+
+        /***
+         * Connect to P2P
+         */
+        /** Verify if it have a defined node */
+        if (!settings.isNodeNameDefined())
+        {
+            String hostname = "Dicoogle";
+
+            try
+            {
+                InetAddress addr = InetAddress.getLocalHost();
+
+                // Get hostname
+                hostname = addr.getHostName();
+            } catch (UnknownHostException e)
+            {
+            }
+
+            String response = (String) JOptionPane.showInputDialog(null,
+                    "What is the name of the machine?",
+                    "Enter Node name",
+                    JOptionPane.QUESTION_MESSAGE, null, null,
+                    hostname);
+
+            settings.setNodeName(response);
+            settings.setNodeNameDefined(true);
+
+            // Save Settings in XML
+            XMLSupport _xml = new XMLSupport();
+            _xml.printXML();
+        }
+
+        logger.debug("Name: {}", ServerSettings.getInstance().getNodeName());
+        
+        TransferSyntax.add(new TransferSyntax("1.2.826.0.1.3680043.2.682.1.40", false,false, false, true));
+        TransferSyntax.add(new TransferSyntax("1.2.840.10008.1.2.4.70", true,false, false, true));
+        TransferSyntax.add(new TransferSyntax("1.2.840.10008.1.2.5.50", false,false, false, true));    
+
+        PluginController PController = PluginController.getInstance();
+
+        // Start the Inicial Services of Dicoogle
+        pt.ua.dicoogle.server.ControlServices.getInstance();
+
+        // Lauch Async Index 
+        // It monitors a folder, and when a file is touched an event
+        // triggers and index is updated.
+        if (ServerSettings.getInstance().isMonitorWatcher()) {
+            AsyncIndex asyncIndex = new AsyncIndex();
+        }
+        //Signals that this application is GUI Server
+        isGUIServer = true;
+
+        //GUIServer GUIserv = new GUIServer();
+    }
+
+    @Deprecated
+    private static void LaunchGUIClient()
+    {
+
+        /* Load all Client Settings from XML */
+        ClientSettings settings = new XMLClientSupport().getXML();
+
+        if (isGUIServer)
+        {
+            remoteGUIPort = ServerSettings.getInstance().getRemoteGUIPort();
+
+            RunClient rc = new RunClient();
+            rc.run();
+        } else
+        {
+            ConnectWindow.getInstance();
+        }
+
+    }
+
+    public static boolean isFixedClient()
+    {
+        return isFixedClient;
+    }
+
+    public static int getRemoteGUIPort()
+    {
+        return remoteGUIPort;
+    }
+
+    private static Set<InetAddress> localAddresses() throws SocketException
+    {
+        Set<InetAddress> localAddrs = new HashSet<>();
+
+        /*Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+
+        while (ifaces.hasMoreElements()) {
+        NetworkInterface iface = ifaces.nextElement();
+        Enumeration<InetAddress> addrs = iface.getInetAddresses();
+        while (addrs.hasMoreElements())
+        localAddrs.add(addrs.nextElement());
+        }
+         *
+         */
+        InetAddress in;
+        try
+        {
+            in = InetAddress.getLocalHost();
+            InetAddress[] all = InetAddress.getAllByName(in.getHostName());
+            localAddrs.addAll(Arrays.asList(all));
+
+        } catch (UnknownHostException ex)
+        {
+            logger.error(ex.getMessage(), ex);
+        }
+
+        return localAddrs;
+    }
+
+    /**
+     *
+     * @param addrs
+     * @return
+     */
+    private static String addressString(Collection<InetAddress> addrs)
+    {
+        String s = "";
+        for (InetAddress addr : addrs)
+        {
+            if (addr.isLoopbackAddress())
+            {
+                continue;
+            }
+            if (s.length() > 0)
+            {
+                s += "!";
+            }
+            s += addr.getHostAddress();
+        }
+        return s;
+    }
+
+    private static class RunClient implements Runnable
+    {
+
+        @Override
+        public void run()
+        {
+            ConnectWindow.getInstance();
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/SystemInfo.java b/dicoogle/src/main/java/pt/ua/dicoogle/SystemInfo.java
new file mode 100755
index 0000000..d982d0a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/SystemInfo.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import org.slf4j.LoggerFactory;
+import javax.swing.filechooser.FileSystemView;
+
+/**
+ * System information methods
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author psytek
+ */
+public class SystemInfo{
+
+    public static File getHomeDirectory(){
+        File result = null;
+        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1){
+            try {
+                Process p = Runtime.getRuntime().exec("cmd /c echo %HOMEDRIVE%%HOMEPATH%");
+                BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+                try{
+                    p.waitFor();
+                }
+                catch (InterruptedException e) {
+                    throw new IOException("Interrupted: " + e.getMessage());
+                }
+                result = new File(reader.readLine());
+            }
+            catch (IOException ex) {
+                LoggerFactory.getLogger(SystemInfo.class.getName()).error(ex.getMessage(), ex);
+            }
+        }
+        else{
+            result = FileSystemView.getFileSystemView().getHomeDirectory();
+        }
+        return result;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/common/ExtensionFilter.java b/dicoogle/src/main/java/pt/ua/dicoogle/common/ExtensionFilter.java
new file mode 100755
index 0000000..7042a92
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/common/ExtensionFilter.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.common;
+
+import java.io.File;
+import javax.swing.filechooser.FileFilter;
+
+
+/**
+ * This class is used to filter file types (extensions) on JFileChooser
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ *
+ */
+public class ExtensionFilter extends FileFilter {
+
+    private String extensions[];
+    private String description;
+
+    public ExtensionFilter(String description, String extension) {
+        this(description, new String[]{extension});
+    }
+
+    public ExtensionFilter(String description, String extensions[]) {
+        this.description = description;
+        this.extensions = (String[]) extensions.clone();
+    }
+
+    @Override
+    public boolean accept(File file) {
+        if (file.isDirectory()) {
+            return true;
+        }
+        int count = extensions.length;
+        String path = file.getAbsolutePath();
+        for (int i = 0; i < count; i++) {
+            String ext = extensions[i];
+            if (path.endsWith(ext)
+                    && (path.charAt(path.length() - ext.length()) == '.')) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String getDescription() {
+        return (description == null ? extensions[0] : description);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/config/Client_Truststore b/dicoogle/src/main/java/pt/ua/dicoogle/config/Client_Truststore
new file mode 100755
index 0000000..c6d8894
Binary files /dev/null and b/dicoogle/src/main/java/pt/ua/dicoogle/config/Client_Truststore differ
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/config/Server_Keystore b/dicoogle/src/main/java/pt/ua/dicoogle/config/Server_Keystore
new file mode 100755
index 0000000..8520a5c
Binary files /dev/null and b/dicoogle/src/main/java/pt/ua/dicoogle/config/Server_Keystore differ
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/config/services.properties b/dicoogle/src/main/java/pt/ua/dicoogle/config/services.properties
new file mode 100755
index 0000000..1252f17
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/config/services.properties
@@ -0,0 +1,2 @@
+webservice = pt.ua.dicoogle.server.web.services.WebService
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/AsyncIndex.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/AsyncIndex.java
new file mode 100755
index 0000000..ffcba8e
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/AsyncIndex.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.commons.io.monitor.FileAlterationListener;
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+import org.apache.commons.io.monitor.FileAlterationMonitor;
+import org.apache.commons.io.monitor.FileAlterationObserver;
+import org.slf4j.LoggerFactory;
+
+
+import org.slf4j.Logger;
+import pt.ua.dicoogle.plugins.PluginController;
+
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class AsyncIndex {
+    private static final Logger logger = LoggerFactory.getLogger(AsyncIndex.class);
+    private final long pollingInterval = 30 * 1000;
+
+    public AsyncIndex() {
+
+        // path to watch
+        String path = ServerSettings.getInstance().getDicoogleDir();
+
+
+        FileAlterationObserver observer = new FileAlterationObserver(path);
+        FileAlterationMonitor monitor =
+                new FileAlterationMonitor(pollingInterval);
+        FileAlterationListener listener = new FileAlterationListenerAdaptor() {
+            // Is triggered when a file is created in the monitored folder
+            @Override
+            public void onFileCreate(File file) {
+
+
+                try {
+                    logger.debug("created {} : {}", file.toPath(), file.toURI());
+                    URI uri = file.toURI();
+                    PluginController.getInstance().index(uri);
+                } catch (Exception ex) {
+                    logger.error(ex.getMessage(), ex);
+                }
+
+
+            }
+            // Is triggered when a file is deleted from the monitored folder
+            @Override
+            public void onFileDelete(File file) {
+                try {
+                    // "file" is the reference to the removed file
+                    System.out.println("File removed: "
+                            + file.getCanonicalPath());
+                    // "file" does not exists anymore in the location
+                    System.out.println("File still exists in location: "
+                            + file.exists());
+
+                    logger.debug("deleted {} : {}", file.toPath(), file.toURI());
+                    try {
+                        URI uri = file.toURI();
+                        PluginController.getInstance().unindex(uri);
+                    } catch (Exception ex) {
+                        logger.error(ex.getMessage(), ex);
+                    }
+                } catch (IOException e) {
+                    e.printStackTrace(System.err);
+                }
+            }
+        };
+        observer.addListener(listener);
+        monitor.addObserver(observer);
+        try {
+            monitor.start();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/ClientSettings.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/ClientSettings.java
new file mode 100755
index 0000000..131c0ee
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/ClientSettings.java
@@ -0,0 +1,159 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import pt.ua.dicoogle.server.users.HashService;
+
+/**
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ * @see XMLClientSupport
+ *
+ */
+public class ClientSettings {
+
+    private String tempFilesDir;
+    private String externalViewer;
+    private String defaultServerHost;
+    private int defaultServerPort;
+    private String defaultUserName;
+    private String defaultPassword;
+    private boolean autoConnect;
+    
+    private static ClientSettings instance = null;
+
+    public static synchronized ClientSettings getInstance()
+    {
+        if (instance == null) {
+            instance = new ClientSettings();
+        }
+        return instance;
+    }
+
+    private ClientSettings() {
+        tempFilesDir = "";
+        externalViewer = "";
+        defaultServerHost = "";
+        defaultServerPort = 0;
+        defaultUserName = "";
+        defaultPassword = "";
+    }
+
+    public void setDefaultSettings()
+    {
+        tempFilesDir = System.getProperty("java.io.tmpdir");
+        externalViewer = "";
+        defaultServerHost = "localhost";
+        defaultServerPort = 9014;
+        defaultUserName = "dicoogle";
+        defaultPassword = HashService.getSHA1Hash("dicoogle");
+    }
+
+    public void setExtV(String EV)
+    {
+        externalViewer = EV;
+    }
+
+    public String getExtV()
+    {
+        return externalViewer;
+    }
+
+    /**
+     * @return the defaultServerHost
+     */
+    public String getDefaultServerHost() {
+        return defaultServerHost;
+    }
+
+    /**
+     * @param defaultServerHost the defaultServerHost to set
+     */
+    public void setDefaultServerHost(String defaultServerHost) {
+        this.defaultServerHost = defaultServerHost;
+    }
+
+    /**
+     * @return the defaultServerPort
+     */
+    public int getDefaultServerPort() {
+        return defaultServerPort;
+    }
+
+    /**
+     * @param defaultServerPort the defaultServerPort to set
+     */
+    public void setDefaultServerPort(int defaultServerPort) {
+        this.defaultServerPort = defaultServerPort;
+    }
+
+    /**
+     * @return the tempFilesDir
+     */
+    public String getTempFilesDir() {
+        return tempFilesDir;
+    }
+
+    /**
+     * @param tempFilesDir the tempFilesDir to set
+     */
+    public void setTempFilesDir(String tempFilesPath) {
+        this.tempFilesDir = tempFilesPath;
+    }
+
+    /**
+     * @return the defaultUserName
+     */
+    public String getDefaultUserName() {
+        return defaultUserName;
+    }
+
+    /**
+     * @param defaultUserName the defaultUserName to set
+     */
+    public void setDefaultUserName(String defaultUserName) {
+        this.defaultUserName = defaultUserName;
+    }
+
+    /**
+     *
+     * @return the default password
+     */
+    public String getDefaultPassword(){
+       return defaultPassword;
+    }
+
+    /**
+     *
+     * @param passHash - new default password
+     */
+    public void setDefaultPassword(String passHash){
+        defaultPassword = passHash;
+    }
+
+    public boolean getAutoConnect(){
+        return autoConnect;
+    }
+
+    public void setAutoConnect(boolean value){
+        autoConnect = value;
+    }
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/ExportDataSupport.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/ExportDataSupport.java
new file mode 100755
index 0000000..4718637
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/ExportDataSupport.java
@@ -0,0 +1,238 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+import pt.ua.dicoogle.rGUI.server.controllers.Search;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+
+
+/**
+ * This class is used to export query results to .csv file format with the selected tags
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ *
+ */
+public class ExportDataSupport extends Observable implements Observer, Serializable {
+    private String query;
+    private HashMap<String, Boolean> origin;
+    //private boolean network;
+    private boolean keywords;
+    private ArrayList<String> tags;
+    private String filePath;
+
+    private ListObservableSearch obsAux = null;
+
+    
+    public ExportDataSupport(String query, HashMap<String, Boolean> origin, boolean keywords, ArrayList<String> tags, String filePath) throws Exception
+    {
+        
+        //System.out.println("Plugins: " + origin);
+        
+        //System.out.println("Entenring...");
+        this.query = query;
+        this.origin = origin;
+        this.keywords = keywords;
+        this.tags = tags;
+        this.filePath = filePath;
+
+        if(!this.filePath.endsWith(".csv"))
+            this.filePath = this.filePath + ".csv";
+
+    }
+
+    public void InitiateExport(Observer obs) throws Exception
+    {
+        this.addObserver(obs);
+        //this.obsAux = obs;
+        //System.out.println("Count observables: "+this.countObservers());
+        //System.out.println("1 - initiateExport");
+        printFirstLine();
+        //System.out.println("2 - initiateExport");
+        //Result2Tree.getInstance().searchToExport(query, keywords, origin, tags, this);
+        ISearch search = new Search();
+        obsAux  = search.SearchToExport(query, keywords, origin, tags, this);
+        //System.out.println("3 - initiateExport"); 
+    }
+
+    /**
+     * Print the first line of the .csv file
+     *
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    private void printFirstLine() throws IOException, InterruptedException{
+        StringBuffer st = new StringBuffer();
+        //System.out.println("Write the First Line");
+        for(String tag: tags)
+            st.append(tag).append(';');
+
+        st.append('\n');
+        //System.out.println("Count observables: "+this.countObservers());
+        printToFile(st);
+    }
+
+    private void printLines(ArrayList<SearchResult> results) throws InterruptedException, IOException{
+        //System.out.println("Count observables: "+this.countObservers());
+        StringBuffer st = new StringBuffer();
+        long i = 0 ; 
+        //System.out.println("Calling");
+        for(SearchResult result : results){
+            
+            //System.out.println("Export: " + i );
+            //System.out.println("Count observables: "+this.countObservers());
+            
+            HashMap<String, Object> extraFields = result.getExtraData();
+            
+            for(String tag: tags){
+                Object temp1 = extraFields.get(tag);
+                String temp = null;
+                if(temp1 instanceof String)
+                    temp = (String) temp1;
+                
+                if(temp == null)
+                {
+                    st.append(';');
+                }
+                else{
+                    temp = temp.replace("\n", "");
+                    temp = temp.replace(";", ",");
+                    st.append(temp).append(';');
+                }
+            }
+            st.append('\n');
+            if (i%1000==0)
+            {
+                BufferedWriter out = new BufferedWriter(new FileWriter(filePath, true));
+                out.write(st.toString());
+                out.close();
+                st = new StringBuffer();
+            }
+            i++;
+            
+        }
+        //System.out.println("Out of loop");
+        // Print last buffer (that is not yet printed)
+        printToFile(st);
+
+        // only intended to notify the observers of the fist time
+        //System.out.println("Calling observables: "+this.countObservers());
+        if(this.countObservers() > 0)
+        {
+            //System.out.println("Calling observables. There is one, at least.");
+            this.setChanged();
+            
+            if (obsAux!=null)
+            {
+                LoggerFactory.getLogger(ExportDataSupport.class).error("obsAux " + obsAux.isFinish() );
+                this.notifyObservers(obsAux.isFinish());
+            }
+            else
+            {
+                LoggerFactory.getLogger(ExportDataSupport.class).error("not obsAux " );
+                this.notifyObservers(false);
+            }
+            //this.deleteObservers();
+        }
+    }
+
+    private void printToFile(StringBuffer st) throws InterruptedException, IOException{
+        
+        BufferedWriter out = new BufferedWriter(new FileWriter(filePath, true));
+        out.write(st.toString());
+        out.close();
+
+    }
+
+    private int count = 0 ; 
+    
+    @Override
+    public synchronized  void update(Observable o, Object arg) {
+        count++ ;
+        
+        if (obsAux==null)
+        {
+
+            obsAux = ((ListObservableSearch) o);
+        }
+        LoggerFactory.getLogger(ExportDataSupport.class).error("Update @ obs");
+        ArrayList tmp = ((ListObservableSearch) o).getArray();
+        
+        if (tmp==null)
+        {
+            tmp = ((ListObservableSearch) obsAux).getArray();
+        }
+        
+        if (tmp==null)
+        {
+            LoggerFactory.getLogger(ExportDataSupport.class).error("Update is null, sending block signal");
+            PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_BLOCK_SIGNAL, null, null));
+            return;
+        }
+        
+        boolean finish = ((ListObservableSearch) obsAux).isFinish();
+        LoggerFactory.getLogger(ExportDataSupport.class).error("Finished @ " + finish);
+        if (finish)
+        {
+            // only intended to notify the observers of the fist time
+            if(this.countObservers() > 0)
+            {
+                this.setChanged();
+                this.notifyObservers((Boolean)finish);
+                obsAux = null;
+                this.deleteObservers();
+            }
+        }   
+        
+        if(tmp instanceof ArrayList) 
+        {
+            try
+            {
+                
+                ArrayList<SearchResult> results = (ArrayList<SearchResult>) tmp;
+                if (results.isEmpty())
+                {
+                    PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_BLOCK_SIGNAL, null, null));
+                    return;
+                }
+                LoggerFactory.getLogger(ExportDataSupport.class).error("Print lines");
+                printLines(results);
+                PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_BLOCK_SIGNAL, null, null));
+
+            } catch (Exception ex) 
+            {
+                LoggerFactory.getLogger(ExportDataSupport.class).error(ex.getMessage(), ex);
+            }
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryExpressionBuilder.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryExpressionBuilder.java
new file mode 100755
index 0000000..d6f0960
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryExpressionBuilder.java
@@ -0,0 +1,203 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** 
+ * Based on a String it will able to separate the strings
+ * and it will be easly extended
+ *
+ * NOTE:
+ * The main proposal of the class is that Search GUI call it
+ * and further for QueryRetrieve Service
+ * 
+ */
+package pt.ua.dicoogle.core;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class QueryExpressionBuilder
+{
+
+    private ArrayList <String> tokens = null ;
+
+    private ArrayList <String> tags = null ;
+
+
+
+    public QueryExpressionBuilder(String text, ArrayList tags)
+    {
+        this(text);
+        this.tags = tags ;
+    }
+
+
+    public QueryExpressionBuilder(String freetext)
+    {
+
+            setTokens(new ArrayList<String>());
+
+            freetext = freetext.replace("^", " ");
+
+             StringTokenizer st = new StringTokenizer(freetext);
+
+             /** XXX probably it can be improved, there're some strange charsets
+              * put it up set
+              */
+
+             while (st.hasMoreTokens())
+             {
+               String ss = st.nextToken();
+               if (ss.contains("^"))
+               {
+                    for (String newToken : ss.split("^"))
+                        tokens.add(newToken);
+
+               }
+               else
+                tokens.add(ss);
+             }
+
+
+             /**
+              * Get tags ;
+              * it it allocated in Run Time, so I have instance access to
+              * singletone
+              */
+
+             TagsStruct _tags = TagsStruct.getInstance();
+
+             this.tags = _tags.getDIMAlias();
+
+    }
+
+    /**
+     * @return the tokens
+     */
+    public ArrayList<String> getTokens()
+    {
+        return tokens;
+    }
+
+    /**
+     * @param tokens the tokens to set
+     */
+    public void setTokens(ArrayList<String> tokens)
+    {
+        this.tokens = tokens;
+    }
+
+
+    public String getQueryString()
+    {
+        /** It will be used to call the Lucene - Indexer
+         * It crucial respect the BNF grammer able to search in library
+         */
+        String queryString = "" ;
+
+
+        /** Search in Lucene in freetext is non-Trivial
+         *  There are some constrains by the library Lunce 2.X
+         *  it was implemented with the repeat of fields
+         *
+         *  Get it for free text: "Smith CT", where the tags domain is:
+         *  PatientName and Modality
+         *
+         *  the result should be:
+         *
+         *  (PatientName=Smith OR Modality=Smith) OR
+         *  (PatientName=CT OR Modality=CT)
+         *
+         *  More general expression was:
+         *  (field1=a1 or field2=a1 or field3=a3 .. or fieldn=an) or
+         *  (...)
+         *  (field1=z1 or field2=z2 or field3=z3 .. or fiendn=zn)
+         *
+         *  This way the search will be in free text really
+         *
+         */
+
+        Iterator<String> itTokens = tokens.iterator();
+        Iterator<String> itTags;
+
+        String token = null ;
+
+        /** Build the query string
+         *
+         * Iterating for each token
+         */
+        while(itTokens.hasNext())
+        {
+            /**
+             * Iterating each tags
+             */
+            queryString += "(";
+            String tag = null ;
+
+            token = itTokens.next();
+            itTags = tags.iterator();
+            while (itTags.hasNext())
+            {
+
+                tag = itTags.next();
+                queryString += tag+":"+token ;
+                /**
+                 * If it have next then the logical condition will continue
+                 * in next iteration
+                 */
+                if (itTags.hasNext())
+                {
+                    queryString += " OR ";
+                }
+            }
+            queryString += "OR others:" + token + " )";
+
+            if (itTokens.hasNext())
+            {
+                queryString += " AND ";
+            }
+
+        }
+
+        return queryString;
+    }
+
+    /**
+     * @return the tags
+     */
+    public ArrayList<String> getTags()
+    {
+        return tags;
+    }
+
+    /**
+     * @param tags the tags to set
+     */
+    public void setTags(ArrayList<String> tags)
+    {
+        this.tags = tags;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistoryEntry.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistoryEntry.java
new file mode 100755
index 0000000..bc9729b
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistoryEntry.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import java.util.AbstractMap.SimpleEntry;
+
+/**
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ */
+public class QueryHistoryEntry<K, V> extends SimpleEntry<K, V> {
+
+    public QueryHistoryEntry(K key, V value){
+        super(key, value);
+    }
+
+    @Override
+    public String toString(){
+        return super.getKey().toString();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistorySupport.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistorySupport.java
new file mode 100755
index 0000000..7882b49
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryHistorySupport.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Observable;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ */
+public class QueryHistorySupport extends Observable {
+
+    //consider replacing this data type "ArrayList<SimpleEntry<String, Boolean>>"
+    private ArrayList<QueryHistoryEntry<String, Boolean>> queryHistory;
+
+    private static String fileName = Platform.homePath() + "QueryHistory.ser";
+
+    private static QueryHistorySupport instance = null;
+
+    public static synchronized QueryHistorySupport getInstance()
+    {
+        if (instance == null) {
+            instance = new QueryHistorySupport();
+        }
+        return instance;
+    }
+
+    private QueryHistorySupport(){
+        if(!loadQueryHistory())
+            queryHistory = new ArrayList<QueryHistoryEntry<String, Boolean>>();
+
+    }
+
+    private boolean loadQueryHistory(){
+        try {
+            ObjectInput in = new ObjectInputStream(new FileInputStream(fileName));
+            queryHistory = (ArrayList<QueryHistoryEntry<String, Boolean>>) in.readObject();
+            in.close();
+
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    public Iterator<QueryHistoryEntry<String, Boolean>> getQueryHistory(){
+        return queryHistory.iterator();
+    }
+
+    public boolean saveQueryHistory(){
+        try {
+            ObjectOutput out = new ObjectOutputStream(new FileOutputStream(fileName));
+            out.writeObject(queryHistory);
+            out.close();
+
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    public void addQuery(String query, boolean keywords){
+        QueryHistoryEntry<String, Boolean> entry = new QueryHistoryEntry<String, Boolean>(query, keywords);
+
+        if(!queryHistory.contains(entry))
+            queryHistory.add(entry);
+        
+        setChanged();
+        notifyObservers();
+    }
+
+    public boolean deleteQuery(QueryHistoryEntry<String, Boolean> entry){
+        boolean result = queryHistory.remove(entry);
+        
+        setChanged();
+        notifyObservers();
+
+        return result;
+    }
+
+    public void deleteAll(){
+        queryHistory.clear();
+
+        setChanged();
+        notifyObservers();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryResultRecord.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryResultRecord.java
new file mode 100755
index 0000000..5f28744
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/QueryResultRecord.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.core;
+
+/**
+ *
+ * @author carloscosta
+ * @MarkedForDeath currently unused
+ */
+public class QueryResultRecord {
+    private String patientName;
+    private String PatientID;
+    private String Modality;
+    private String StudyDate;
+    private String FilePath;
+    private byte[] Thumbnail;
+
+    public QueryResultRecord(String patientName, String PatientID, 
+                             String Modality, String StudyDate, 
+                             String FilePath, byte[] Thumbnail){
+        this.patientName = patientName;
+        this.PatientID = PatientID;
+        this.Modality = Modality;
+        this.StudyDate = StudyDate;
+        this.FilePath = FilePath;
+        this.Thumbnail = Thumbnail;
+    }
+    
+    public String getPatientName() {
+        return patientName;
+    }
+
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+    public String getPatientID() {
+        return PatientID;
+    }
+
+    public void setPatientID(String PatientID) {
+        this.PatientID = PatientID;
+    }
+
+    public String getModality() {
+        return Modality;
+    }
+
+    public void setModality(String Modality) {
+        this.Modality = Modality;
+    }
+
+    public String getStudyDate() {
+        return StudyDate;
+    }
+
+    public void setStudyDate(String StudyDate) {
+        this.StudyDate = StudyDate;
+    }
+
+    public String getFilePath() {
+        return FilePath;
+    }
+
+    public void setFilePath(String FilePath) {
+        this.FilePath = FilePath;
+    }
+
+    public byte[] getThumbnail() {
+        return Thumbnail;
+    }
+        
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/ServerSettings.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/ServerSettings.java
new file mode 100755
index 0000000..153ed35
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/ServerSettings.java
@@ -0,0 +1,1338 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import org.dcm4che2.data.UID;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.core.ServerSettingsReader;
+import pt.ua.dicoogle.sdk.core.WebSettingsReader;
+
+import pt.ua.dicoogle.server.web.utils.types.DataTable;
+
+/** Singleton class of all server settings.
+ *
+ * @author Marco Pereira
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author António Novo <antonio.novo at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ * @see XMLSupport
+ */
+public class ServerSettings implements ServerSettingsReader
+{
+    private String AETitle;
+
+    //Access List Settings
+    private String [] CAETitle;
+    private boolean permitAllAETitles;
+
+    private String Path;
+    private String ID;
+    private int storagePort;
+
+    @Deprecated
+    private int rGUIPort;
+    @Deprecated
+    private String RGUIExternalIP;
+
+    //Dicoogle Settings
+    private String dicoogleDir;
+    private boolean fullContentIndex;
+    private boolean saveThumbnails;
+    private String thumbnailsMatrix;
+    //private boolean P2P;
+
+    private boolean storage;
+    private boolean queryRetrieve;
+    private boolean encryptUsersFile;
+
+    /** 
+     * Indicates, for each plugin, if it is to start at server init or not.
+     */
+    private final ConcurrentHashMap<String, Boolean> autoStartPlugin; // NOTE the concurrent hash map is used to prevent having to synchronize the methods that use it
+
+    /**
+     * The name of the Remote GUI setting that indicates the External IP address.
+     */
+    public static final String RGUI_SETTING_EXTERNAL_IP = "External IP";
+
+    /**
+     * The name of the Query Retrieve setting that indicates the Maximum number of Client Associations.
+     */
+    public static final String QUERYRETRIEVE_MAX_ASSOCIATIONS = "Max. Associations";
+    /**
+     * The name of the Query Retrieve setting that indicates the Maximum PDU Length Receive.
+     */
+    public static final String QUERYRETRIEVE_MAX_PDU_RECEIVE = "Max. PDU Receive";
+    /**
+     * The name of the Query Retrieve setting that indicates the Maximum PDU Length Send.
+     */
+    public static final String QUERYRETRIEVE_MAX_PDU_SEND = "Max. PDU Send";
+    /**
+     * The name of the Query Retrieve setting that indicates the Idle Timeout.
+     */
+    public static final String QUERYRETRIEVE_IDLE_TIMEOUT = "Idle Timeout";
+    /**
+     * The name of the Query Retrieve setting that indicates the Accpet Timeout.
+     */
+    public static final String QUERYRETRIEVE_ACCEPT_TIMEOUT = "Accept Timeout";
+    /**
+     * The name of the Query Retrieve setting that indicates the Response Timeout.
+     */
+    public static final String QUERYRETRIEVE_RESPONSE_TIMEOUT = "Response Timeout";
+    /**
+     * The name of the Query Retrieve setting that indicates the Connection Timeout.
+     */
+    public static final String QUERYRETRIEVE_CONNECTION_TIMEOUT = "Connection Timeout";
+
+    /**
+     * The name of the Storage setting that indicates the Servers Destinations.
+     */
+    public static final String STORAGE_SETTING_SERVERS_DESTINATIONS = "Storage Servers Destinations";
+    /**
+     * The name of the Storage setting that indicates the Storage Path.
+     */
+    public static final String STORAGE_SETTING_PATH = "Storage Path";
+
+    /**
+     * The help for the Remote GUI External IP setting.
+     */
+    public static final String RGUI_SETTING_EXTERNAL_IP_HELP = "If your Dicoogle GUI Server is running behind a router, you need to provide your external IP address to have access from outside of the router.\nBesides that, you need to configure your router to open the Remote GUI Port!";
+
+    /**
+     * QueryRetrieve Server
+     */
+    
+    private boolean wlsOn = false ; 
+    
+    /* DEFAULT Brief class description */
+    private String deviceDescription ;
+    /* DEFAULT Process Worklist Server AE Title */
+    private String localAETName ;
+    
+    /* DEFAULT ("any"->null)Permited local interfaces to incomming connection
+     * ('null'->any interface; 'ethx'->only this interface |->separator */
+    private String permitedLocalInterfaces ;
+    
+    /* DEFAULT ("any"->null)Permited remote host name connections
+     * ('null'->any can connect; 'www.x.com'->only this can connect |->separator */
+    private String permitedRemoteHostnames ; 
+    
+    /* DEFAULT Dimse response timeout (in sec) */
+    private int DIMSERspTimeout ;
+    // Connection settings
+    
+    /* DEFAULT Listening TCP port */
+    private int wlsPort ;
+    /* DEFAULT Response delay (in miliseconds) */
+    private int rspDelay ;
+    /* DEFAULT Idle timeout (in sec) */
+    private int idleTimeout ;
+    /* DEFAULT Accept timeout (in sec) */
+    private int acceptTimeout ;
+    /* DEFAULT Connection timeout (in sec) */
+    private int connectionTimeout ;
+    
+    private int maxMessages = 2000;
+    private String SOPClass  ; 
+    private String transfCAP ; 
+    
+     /* DEFAULT Max Client Associations */
+    private int maxClientAssocs  ; 
+   
+    private int maxPDULengthReceive ;
+    private int maxPDULengthSend ;
+
+
+    HashMap<String, String> modalityFind = new HashMap<>();
+
+    ArrayList<MoveDestination> dest = new ArrayList<>();
+
+    private Set<String> priorityAETitles = new HashSet<>();
+
+    private boolean indexAnonymous = false;
+
+    private boolean indexZIPFiles = true;
+    
+    private boolean monitorWatcher = false;
+
+    /**
+     * P2P
+     */
+
+    private String p2pLibrary = "JGroups";
+    private String nodeName = "Dicoogle";
+    private boolean nodeNameDefined = false ;
+
+    private String networkInterfaceName ="";
+
+    /** Indexer */
+    private String indexer = "lucene2.2";
+    private int indexerEffort = 0 ;
+    private HashSet<String> extensionsAllowed = new HashSet<>();
+
+    private boolean gzipStorage = false;
+    private final String aclxmlFileName = "aetitleFilter.xml";
+
+    /**
+     * @return the web
+     */
+    @Override
+    public Web getWeb()
+    {
+        return web;
+    }
+
+    /**
+     * @param web the web to set
+     */
+    public void setWeb(Web web)
+    {
+        this.web = web;
+    }
+
+    /**
+     * @return the p2pLibrary
+     */
+    public String getP2pLibrary() {
+        return p2pLibrary;
+    }
+
+    /**
+     * @param p2pLibrary the p2pLibrary to set
+     */
+    public void setP2pLibrary(String p2pLibrary) {
+        this.p2pLibrary = p2pLibrary;
+    }
+
+    /**
+     * @return the indexer
+     */
+    @Override
+    public String getIndexer() {
+        return indexer;
+    }
+
+    /**
+     * @param indexer the indexer to set
+     */
+    public void setIndexer(String indexer) {
+        this.indexer = indexer;
+    }
+
+    /**
+     * @return the nodeName
+     */
+    @Override
+    public String getNodeName() {
+        return nodeName;
+    }
+
+    /**
+     * @param nodeName the nodeName to set
+     */
+    public void setNodeName(String nodeName) {
+        this.nodeName = nodeName;
+    }
+
+    /**
+     * @return the nodeNameDefined
+     */
+    @Override
+    public boolean isNodeNameDefined() {
+        return nodeNameDefined;
+    }
+
+    /**
+     * @param nodeNameDefined the nodeNameDefined to set
+     */
+    public void setNodeNameDefined(boolean nodeNameDefined) {
+        this.nodeNameDefined = nodeNameDefined;
+    }
+
+    @Override
+    public String getNetworkInterfaceName()
+    {
+        return networkInterfaceName;
+    }
+
+    public void setNetworkInterfaceName(String interfaceName)
+    {
+        this.networkInterfaceName = interfaceName;
+    }
+
+
+    /**
+     * @return the indexerEffort
+     */
+    @Override
+    public int getIndexerEffort() {
+        return indexerEffort;
+    }
+
+    /**
+     * @param indexerEffort the indexerEffort to set
+     */
+    public void setIndexerEffort(int indexerEffort) {
+        this.indexerEffort = indexerEffort;
+    }
+
+    /**
+     * @return the encryptUsersFile
+     */
+    @Override
+    public boolean isEncryptUsersFile() {
+        return encryptUsersFile;
+    }
+
+    /**
+     * @param encryptUsersFile the encryptUsersFile to set
+     */
+    public void setEncryptUsersFile(boolean encryptUsersFile) {
+        this.encryptUsersFile = encryptUsersFile;
+    }
+
+    /**
+     * @return the indexZIPFiles
+     */
+    @Override
+    public boolean isIndexZIPFiles() {
+        return indexZIPFiles;
+    }
+
+    /**
+     * @param indexZIPFiles the indexZIPFiles to set
+     */
+    public void setIndexZIPFiles(boolean indexZIPFiles) {
+        this.indexZIPFiles = indexZIPFiles;
+    }
+
+    /**
+     * @return the RGUIExternalIP
+     */
+    @Deprecated
+    public String getRGUIExternalIP() {
+        return RGUIExternalIP;
+    }
+
+    /**
+     * @param RGUIExternalIP the RGUIExternalIP to set
+     */
+    @Deprecated
+    public void setRGUIExternalIP(String RGUIExternalIP) {
+        this.RGUIExternalIP = RGUIExternalIP;
+    }
+
+    /**
+     * @return the monitorWatcher
+     */
+    @Override
+    public boolean isMonitorWatcher() {
+        return monitorWatcher;
+    }
+
+    /**
+     * @param monitorWatcher the monitorWatcher to set
+     */
+    public void setMonitorWatcher(boolean monitorWatcher) {
+        this.monitorWatcher = monitorWatcher;
+    }
+
+    /**
+     * @return the indexAnonymous
+     */
+    @Override
+    public boolean isIndexAnonymous() {
+        return indexAnonymous;
+    }
+
+    /**
+     * @param indexAnonymous the indexAnonymous to set
+     */
+    public void setIndexAnonymous(boolean indexAnonymous) {
+        this.indexAnonymous = indexAnonymous;
+    }
+
+    /**
+     * @return the gzipStorage
+     */
+    @Override
+    public boolean isGzipStorage() {
+        return gzipStorage;
+    }
+
+    /**
+     * @param gzipStorage the gzipStorage to set
+     */
+    public void setGzipStorage(boolean gzipStorage) {
+        this.gzipStorage = gzipStorage;
+    }
+
+    @Override
+    public String getAccessListFileName() {
+        return this.aclxmlFileName;
+    }
+
+    /**
+     * Web (including web server, webservices, etc)
+     */
+    public class Web implements WebSettingsReader
+    {
+        private boolean webServer = true;
+        private int serverPort = 8080;
+        private String accessControlAllowOrigins = "*";
+
+        @Deprecated
+        private boolean webServices = false;
+        @Deprecated
+        private int servicePort = 6060;
+        
+
+
+        public Web()
+        {
+        }
+
+        /**
+         * @return the webServer
+         */
+        @Override
+        public boolean isWebServer() {
+            return webServer;
+        }
+
+        /**
+         * @param webServer the webServer to set
+         */
+        public void setWebServer(boolean webServer) {
+            this.webServer = webServer;
+        }
+
+        /**
+         * @return the webServices
+         */
+        @Deprecated
+        public boolean isWebServices() {
+            return webServices;
+        }
+
+        /**
+         * @param webServices the webServices to set
+         */
+        @Deprecated
+        public void setWebServices(boolean webServices) {
+            this.webServices = webServices;
+        }
+
+        /**
+         * @return the serverPort
+         */
+        @Override
+        public int getServerPort() {
+            return serverPort;
+        }
+
+        /**
+         * @param serverPort the serverPort to set
+         */
+        public void setServerPort(int serverPort) {
+            this.serverPort = serverPort;
+        }
+
+        /**
+         * @return the servicePort
+         */
+        @Deprecated
+        public int getServicePort() {
+            return servicePort;
+        }
+
+        /**
+         * @param servicePort the servicePort to set
+         */
+        @Deprecated
+        public void setServicePort(int servicePort) {
+            this.servicePort = servicePort;
+        }
+
+        @Override
+        public String getAllowedOrigins() {
+            return this.accessControlAllowOrigins;
+        }
+
+        public void setAllowedOrigins(String origins) {
+            this.accessControlAllowOrigins = origins;
+        }
+
+    }
+
+    private Web web = new Web();
+
+	private boolean wanmode;
+
+    private static ServerSettings instance = null;
+    
+    public static synchronized ServerSettings getInstance()
+    {
+        if (instance == null) {
+            instance = new ServerSettings();
+        }
+        return instance;
+    }
+
+    private ServerSettings()
+    {
+        rGUIPort = 9014;
+        storagePort = 104;
+        AETitle = "DICOOGLE";
+        CAETitle = new String[0];
+        permitAllAETitles = true;
+        Path = "";
+        dicoogleDir = "";
+        fullContentIndex = false;
+        saveThumbnails = false;
+        thumbnailsMatrix = "64";
+
+        encryptUsersFile = false;
+
+        /**
+         * Set default values of QueryRetrieve Server
+         */
+
+        this.deviceDescription = "Dicoogle - Server SCP" ;
+        this.localAETName  = "Dicoogle";
+        this.permitedLocalInterfaces = "any";
+        this.permitedRemoteHostnames = "any";
+        this.wlsPort = 1045 ;  // default: 104
+        this.idleTimeout = 60 ;
+        this.acceptTimeout = 60 ;
+        this.rspDelay = 0 ;        
+        this.DIMSERspTimeout = 60 ;
+        this.connectionTimeout = 60 ;
+        
+        this.transfCAP = UID.ImplicitVRLittleEndian + "|" + UID.ExplicitVRBigEndian + "|" + UID.ExplicitVRLittleEndian;     
+
+        this.SOPClass = UID.StudyRootQueryRetrieveInformationModelFIND 
+        + "|" + UID.PatientRootQueryRetrieveInformationModelFIND;
+               
+        fillModalityFindDefault();
+        this.maxClientAssocs = 20 ; 
+        this.maxPDULengthReceive = 16364 ; 
+        this.maxPDULengthSend = 16364 ;
+        System.setProperty("java.net.preferIPv4Stack", "true");
+
+        autoStartPlugin = new ConcurrentHashMap<>();
+    }
+
+    // Nasty bug fix; no thumbnails references here = null pointers
+    public void setDefaultSettings()
+    {
+        rGUIPort = 9014;
+        storagePort = 6666;
+        AETitle = "DICOOGLE-STORAGE";
+        Path = System.getProperty("java.io.tmpdir");
+        CAETitle = new String[0];
+        permitAllAETitles = true;
+        dicoogleDir = System.getProperty("java.io.tmpdir");
+        fullContentIndex = false;
+        saveThumbnails = false;
+        thumbnailsMatrix = "64";
+        autoStartPlugin.clear();
+
+        setEncryptUsersFile(false);
+    }
+
+    public void setAE(String AE)
+    {
+        AETitle = AE;
+    }
+
+    @Override
+    public String getAE()
+    {
+        return AETitle;
+    }
+
+    public void setID(String I)
+    {
+        ID = I;
+    }
+
+    @Override
+    public String getID()
+    {
+        return ID;
+    }
+
+    public void setCAET(String[] CAET)
+    {
+        CAETitle = CAET;            
+    }
+
+    @Override
+    public String[] getCAET()
+    {
+        return CAETitle;
+    }
+
+    public void setPermitAllAETitles(boolean value){
+        permitAllAETitles = value;
+    }
+
+    @Override
+    public boolean getPermitAllAETitles(){
+        return permitAllAETitles;
+    }
+
+    public void setStoragePort(int p)
+    {
+        storagePort = p;
+    }
+
+    public void setPath(String p)
+    {
+        Path = p;
+    }
+
+    @Override
+    public String getPath()
+    {
+        return Path;
+    }
+
+    @Override
+    public int getStoragePort()
+    {
+        return storagePort;
+    }
+
+    @Deprecated
+    public void setRemoteGUIPort(int port){
+        rGUIPort = port;
+    }
+
+    @Deprecated
+    public int getRemoteGUIPort(){
+        return rGUIPort;
+    }
+
+    @Override
+    public String getDicoogleDir() {
+        return dicoogleDir;
+    }
+
+    public void setDicoogleDir(String dicoogleDir) {
+        this.dicoogleDir = dicoogleDir;
+    }
+
+
+    @Override
+    public boolean getFullContentIndex() {
+        return fullContentIndex;
+    }
+
+    public void setFullContentIndex(boolean fullContentIndex) {
+        this.fullContentIndex = fullContentIndex;
+    }
+
+    @Override
+    public boolean getSaveThumbnails() {
+        return saveThumbnails;
+    }
+
+    public void setSaveThumbnails(boolean saveThumbnails) {
+        this.saveThumbnails = saveThumbnails;
+    }
+    
+    @Override
+    public String getThumbnailsMatrix() {
+        return thumbnailsMatrix;
+    }
+
+    public void setThumbnailsMatrix(String thumbnailsMatrix) {
+        this.thumbnailsMatrix = thumbnailsMatrix;
+    }
+
+    /*
+     * Query Retrieve Server
+     */
+
+    public void setWlsPort(int port)
+    {
+        this.wlsPort = port ;
+    }
+
+    @Override
+    public int getWlsPort()
+    {
+        return this.wlsPort ;
+    }
+
+    public void setIdleTimeout(int timeout)
+    {
+        this.idleTimeout = timeout ;
+    }
+
+    @Override
+    public int getIdleTimeout()
+    {
+        return this.idleTimeout ;
+    }
+
+    public void setRspDelay(int delay)
+    {
+        this.rspDelay = delay ;
+    }
+
+    @Override
+    public int getRspDelay()
+    {
+        return this.rspDelay  ;
+    }
+
+    public void setAcceptTimeout(int timeout)
+    {
+        this.acceptTimeout = timeout ;
+    }
+    @Override
+    public int getAcceptTimeout()
+    {
+        return this.acceptTimeout;
+    }
+
+    public void setConnectionTimeout(int timeout)
+    {
+        this.connectionTimeout = timeout; 
+    }
+    @Override
+    public int getConnectionTimeout()
+    {
+        return this.connectionTimeout ;
+    }
+    
+    public void setSOPClass(String SOPClass)
+    {
+        this.SOPClass = SOPClass ;
+    }
+    
+    @Override
+    public String[] getSOPClasses()
+    {
+        String []tmp = {
+            UID.StudyRootQueryRetrieveInformationModelFIND ,
+            UID.PatientRootQueryRetrieveInformationModelFIND
+        };
+        return tmp ; 
+    }
+
+    @Override
+    public String getSOPClass()
+    {
+        return this.SOPClass ; 
+    }
+    public void setDIMSERspTimeout(int timeout)
+    {
+        this.DIMSERspTimeout = timeout ; 
+    }
+    @Override
+    public int getDIMSERspTimeout()
+    {
+        return this.DIMSERspTimeout ; 
+    }
+    public void setDeviceDescription(String desc)
+    {
+        this.deviceDescription = desc ; 
+    }
+    
+    @Override
+    public String getDeviceDescription()
+    {
+        return this.deviceDescription;
+    }
+    
+    public void setTransfCap(String transfCap)
+    {
+        this.transfCAP = transfCap;
+    }
+        
+    @Override
+    public String getTransfCap()
+    {
+        return this.transfCAP; 
+    }
+    
+    public void setMaxClientAssoc(int maxClients)
+    {
+        this.maxClientAssocs = maxClients; 
+    }
+    
+    @Override
+    public int getMaxClientAssoc()
+    {
+        return this.maxClientAssocs; 
+    }
+    
+    public void setMaxPDULengthReceive(int len)
+    {
+        this.maxPDULengthReceive = len;
+    }
+    
+    @Override
+    public int getMaxPDULengthReceive()
+    {
+        return this.maxPDULengthReceive; 
+    }
+    public void setMaxPDULengthSend(int len)
+    {
+        this.maxPDULengthSend = len;
+    }
+    @Override
+    public int getMaxPDULenghtSend() // FIXME typo
+    {
+        return this.maxPDULengthSend; 
+    }
+    
+    public void setLocalAETName(String name)
+    {
+        this.localAETName = name; 
+    }
+    @Override
+    public String getLocalAETName()
+    {
+        return this.localAETName; 
+    }
+    
+    public void setPermitedLocalInterfaces(String localInterfaces)
+    {
+        this.permitedLocalInterfaces  = localInterfaces; 
+    }
+    
+    @Override
+    public String getPermitedLocalInterfaces()
+    {
+        return this.permitedLocalInterfaces; 
+    }
+    
+    public void setPermitedRemoteHostnames(String remoteHostnames)
+    {
+        this.permitedRemoteHostnames = remoteHostnames; 
+    }
+    
+    @Override
+    public String getPermitedRemoteHostnames()
+    {
+        return this.permitedRemoteHostnames;
+    }
+
+    /**
+     * @return the P2P
+     */
+   /* public boolean isP2P() {
+        return P2P;
+    }*/
+    @Override
+    public boolean isStorage() {
+        return storage;
+    }
+    @Override
+    public boolean isQueryRetrive() {
+        return queryRetrieve;
+    }
+
+    public void add(MoveDestination m)
+    {
+        this.dest.add(m);
+    }
+    public boolean remove(MoveDestination m)
+    {
+        return this.dest.remove(m);
+    }
+    public boolean removeMoveDestination(String AETitle, String ipAddr, int port)
+    {
+    	for(int i=0;i<dest.size(); i++)
+    	{
+    		MoveDestination mv = dest.get(i);
+    		if(mv.getAETitle().equals(AETitle) && mv.getIpAddrs().equals(ipAddr) && mv.getPort() == port)
+    		{
+    			dest.remove(i);
+    			return true;
+    		}
+    			
+    	}
+    	return false;
+    }
+
+    public boolean removeMoveDestination(String AETitle)
+    {
+        boolean removed = false;
+        Iterator<MoveDestination> it = dest.iterator();
+        while(it.hasNext()) {
+            if(it.next().getAETitle().equals(AETitle)) {
+                it.remove();
+                removed = true;
+            }
+        }
+        return removed;
+    }
+    public boolean contains(MoveDestination m){
+        return this.dest.contains(m);
+    }
+    @Override
+    public ArrayList<MoveDestination> getMoves()
+    {
+        return this.dest ;
+    }
+
+    @Override
+    public Set<String> getPriorityAETitles() {
+        return priorityAETitles;
+    }
+
+    public void addPriorityAETitle(String aet)
+    {
+        this.priorityAETitles.add(aet);
+    }
+    public void removePriorityAETitle(String aet)
+    {
+        this.priorityAETitles.remove(aet);
+    }
+
+    public void setMoves(ArrayList<MoveDestination> moves)
+    {
+        if(moves != null)
+            this.dest = moves;
+    }
+
+
+
+    private void fillModalityFindDefault()
+    {
+         addModalityFind("1.2.840.10008.5.1.4.1.2.2.1",
+                 "Study Root Query/Retrieve Information Model");
+
+         addModalityFind("1.2.840.10008.5.1.4.1.2.1.1",
+                    "Patient Root Query/Retrieve Information Model"
+                 );
+
+    }
+
+    /**
+     * Set default values
+     */
+    public void setDefaultsValues()
+    {
+        this.fillModalityFindDefault();
+    }
+
+    /**
+     * Add a modality
+     * @param sop Number like 1.2.3.5.6.7.32.1
+     * @param description Description like "Modality Worklist Model"
+     */
+    public void addModalityFind(String sop, String description)
+    {
+        this.modalityFind.put(sop, description);
+    }
+
+    /**
+     *
+     * @return HashMap with Modalitys FIND
+     */
+    @Override
+    public HashMap<String, String> getModalityFind()
+    {
+        return this.modalityFind;
+    }
+
+
+    /**
+     * Sets the plugin start on server init value.
+     * <b>NOTE</b>: this method is strictly for plugins, not embedded services.
+     *
+     * @param name the name of the plugin.
+     * @param value true to auto start the plugin on server init.
+     */
+    public void setAutoStartPlugin(String name, boolean value)
+    {
+    	// remove the previous setting, if there is one
+    	autoStartPlugin.remove(name);
+
+        // insert the new setting
+        autoStartPlugin.put(name, value);
+    }
+
+    /**
+     * Returns if the plugin is to be auto started on server init or not.
+     * The default value (without previous configuration) is to start the plugin.
+     * <b>NOTE</b>: this method is strictly for plugins, not embedded services.
+     *
+     * @param name the name of the plugin.
+     * @return true if the plugin is to be auto started on server init or false if it is not.
+     */
+    @Override
+    public boolean getAutoStartPlugin(String name)
+    {
+    	Boolean result = autoStartPlugin.get(name);
+
+        // if there is not such setting return the default value
+        if (result == null) return true; // by default start the plugin
+        return result.booleanValue();
+    }
+
+	/**
+	 * Returns the current settings for plugin auto start on server init.
+	 *
+	 * @return the current settings for plugin auto start on server init.
+	 */
+    @Override
+	public ConcurrentHashMap<String, Boolean> getAutoStartPluginsSettings()
+	{
+		return autoStartPlugin;
+	}
+
+	/**
+	 * Returns the Remote GUI list of settings (name, value/type pairs).
+	 *
+	 * @return and HashMap containing the Remote GUI list of settings (name, value/type pairs).
+	 */
+    @Deprecated
+	public HashMap<String, Object> getRGUISettings()
+	{
+		HashMap<String, Object> result = new HashMap<String, Object>();
+
+		result.put(RGUI_SETTING_EXTERNAL_IP, getRGUIExternalIP());
+
+		return result;
+	}
+
+	/**
+	 * Validates the new settings for the Remote GUI service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and can be applied, false otherwise.
+	 */
+    @Deprecated
+	public boolean tryRGUISettings(HashMap<String, Object> settings)
+	{
+		// TODO
+		return true;
+	}
+
+	/**
+	 * Tries to apply the new settings for the Remote GUI service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and were applied successfully, false otherwise.
+	 */
+    @Deprecated
+	public boolean setRGUISettings(HashMap<String, Object> settings)
+	{
+		if (! tryRGUISettings(settings))
+			return false;
+
+		setRGUIExternalIP((String) settings.get(RGUI_SETTING_EXTERNAL_IP));
+
+		return true;
+	}
+
+	/**
+	 * Returns the Remote GUI list of settings help (name,help pairs).
+	 *
+	 * @return and HashMap containing the Remote GUI list of settings help (name, help).
+	 */
+	public HashMap<String, String> getRGUISettingsHelp()
+	{
+		HashMap<String, String> result = new HashMap<String, String>();
+	
+		result.put(RGUI_SETTING_EXTERNAL_IP, RGUI_SETTING_EXTERNAL_IP_HELP);
+
+		return result;
+	}
+
+	/**
+	 * Returns the Query Retrieve list of settings (name, value/type pairs).
+	 *
+	 * @return and HashMap containing the Query Retrieve list of settings (name, value/type pairs).
+	 */
+    @Override
+	public HashMap<String, Object> getQueryRetrieveSettings()
+	{
+		HashMap<String, Object> result = new HashMap<>();
+
+		result.put(QUERYRETRIEVE_MAX_ASSOCIATIONS, getMaxClientAssoc());
+		result.put(QUERYRETRIEVE_MAX_PDU_RECEIVE, getMaxPDULengthReceive());
+		result.put(QUERYRETRIEVE_MAX_PDU_SEND, getMaxPDULenghtSend());
+		result.put(QUERYRETRIEVE_IDLE_TIMEOUT, getIdleTimeout());
+		result.put(QUERYRETRIEVE_ACCEPT_TIMEOUT, getAcceptTimeout());
+		result.put(QUERYRETRIEVE_RESPONSE_TIMEOUT, getRspDelay());
+		result.put(QUERYRETRIEVE_CONNECTION_TIMEOUT, getConnectionTimeout());
+
+		return result;
+	}
+
+	/**
+	 * Validates the new settings for the Query Retrieve service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and can be applied, false otherwise.
+	 */
+	public boolean tryQueryRetrieveSettings(HashMap<String, Object> settings)
+	{
+		// TODO
+		return true;
+	}
+
+	/**
+	 * Tries to apply the new settings for the Query Retrieve service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and were applied successfully, false otherwise.
+	 */
+	public boolean setQueryRetrieveSettings(HashMap<String, Object> settings)
+	{
+		if (! tryQueryRetrieveSettings(settings))
+			return false;
+
+		setMaxClientAssoc(((Integer) settings.get(QUERYRETRIEVE_MAX_ASSOCIATIONS)).intValue());
+		setMaxPDULengthReceive(((Integer) settings.get(QUERYRETRIEVE_MAX_PDU_RECEIVE)).intValue());
+		setMaxPDULengthSend(((Integer) settings.get(QUERYRETRIEVE_MAX_PDU_SEND)).intValue());
+		setIdleTimeout(((Integer) settings.get(QUERYRETRIEVE_IDLE_TIMEOUT)).intValue());
+		setAcceptTimeout(((Integer) settings.get(QUERYRETRIEVE_ACCEPT_TIMEOUT)).intValue());
+		setRspDelay(((Integer) settings.get(QUERYRETRIEVE_RESPONSE_TIMEOUT)).intValue());
+		setConnectionTimeout(((Integer) settings.get(QUERYRETRIEVE_CONNECTION_TIMEOUT)).intValue());
+
+		return true;
+	}
+
+	/**
+	 * Returns the Query Retrieve list of settings help (name,help pairs).
+	 *
+	 * @return and HashMap containing the Query Retrieve list of settings help (name, help).
+	 */
+	public HashMap<String, String> getQueryRetrieveSettingsHelp()
+	{
+		return null; // no help available
+	}
+
+	/**
+	 * Returns the Storage list of settings (name, value/type pairs).
+	 *
+	 * @return and HashMap containing the Storage list of settings (name, value/type pairs).
+	 */
+    @Override
+	public HashMap<String, Object> getStorageSettings()
+	{
+		HashMap<String, Object> result = new HashMap<>();
+
+		//result.put(STORAGE_SETTING_PATH, new ServerDirectoryPath(getPath()));
+		// TODO move some of these new classes onto the SDK, so that plugins can also process option types/fields
+		int destCount = dest.size();
+		DataTable storageServers = new DataTable(3, destCount);
+		storageServers.setColumnName(0, "AETitle");
+		storageServers.setColumnName(1, "IP");
+		storageServers.setColumnName(2, "Port");
+		// if there are no rows, then add an empty one (for reference)
+		if (destCount < 1)
+		{
+			storageServers.addRow();
+			storageServers.setCellData(0, 0, "");
+			storageServers.setCellData(0, 1, "");
+			storageServers.setCellData(0, 2, "");
+		}
+		else
+			for (int i = 0; i < destCount; i++)
+			{
+				MoveDestination aDest = dest.get(i);
+				storageServers.setCellData(i, 0, aDest.getAETitle());
+				storageServers.setCellData(i, 1, aDest.getIpAddrs());
+				storageServers.setCellData(i, 2, "" + aDest.getPort());
+			}
+		result.put(STORAGE_SETTING_SERVERS_DESTINATIONS, storageServers);
+
+		return result;
+	}
+
+	/**
+	 * Validates the new settings for the Storage service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and can be applied, false otherwise.
+	 */
+	public boolean tryStorageSettings(HashMap<String, Object> settings)
+	{
+		// TODO
+		return true;
+	}
+
+	/**
+	 * Tries to apply the new settings for the Storage service.
+	 *
+	 * @param settings a HashMap containing the new setting values.
+	 * @return true if all the values are valid and were applied successfully, false otherwise.
+	 */
+	public boolean setStorageSettings(HashMap<String, Object> settings)
+	{
+		if (! tryStorageSettings(settings))
+			return false;
+
+		//setPath(((ServerDirectoryPath) settings.get(STORAGE_SETTING_PATH)).getPath());
+		// TODO set the query retrieve options
+
+		return true;
+	}
+
+	/**
+	 * Returns the Storage list of settings help (name,help pairs).
+	 *
+	 * @return and HashMap containing the Storage list of settings help (name, help).
+	 */
+	public HashMap<String, String> getStorageSettingsHelp()
+	{
+		return null; // no help available
+	}
+
+    public void setStorage(boolean storage)
+    {
+        this.storage = storage;
+    }
+
+    public void setQueryRetrive(boolean queryRetrieve)
+    {
+        this.queryRetrieve = queryRetrieve;
+    }
+
+    @Override
+    public ArrayList<String> getNetworkInterfacesNames()
+    {
+        ArrayList<String> interfaces = new ArrayList<String>();
+        Enumeration<NetworkInterface> nets = null;
+        try
+        {
+            nets = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException ex)
+        {
+            ex.printStackTrace();
+        }
+
+        
+        for (NetworkInterface netint : Collections.list(nets))
+        {
+            try
+            {
+                if (!netint.isLoopback())
+                {
+                    Enumeration<InetAddress> addresses = netint.getInetAddresses();
+                    while (addresses.hasMoreElements())
+                    {
+                        if (Inet4Address.class.isInstance(addresses.nextElement()))
+                        {
+                            interfaces.add(netint.getDisplayName());
+                        }
+                    }
+                }
+            } catch (SocketException ex)
+            {
+                LoggerFactory.getLogger(ServerSettings.class).error(ex.getMessage(), ex);
+            }
+        }
+        return interfaces;
+    }
+
+    @Override
+    public String getNetworkInterfaceAddress()
+    {
+        Enumeration<NetworkInterface> nets = null;
+        try
+        {
+            nets = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException ex)
+        {
+            ex.printStackTrace();
+        }
+
+        for(NetworkInterface netint : Collections.list(nets))
+        {
+            if(netint.getDisplayName().compareTo(this.networkInterfaceName) == 0)
+            {
+                Enumeration<InetAddress> addresses = netint.getInetAddresses();
+                while(addresses.hasMoreElements())
+                {
+                    InetAddress address = addresses.nextElement();
+                    if(Inet4Address.class.isInstance(address))
+                    {
+                        return address.getHostAddress();
+                    }
+                }
+                return null;
+            }
+        }
+        return null;
+    }
+    /**
+     * Add an extension to list of allowed indexing extensions.
+     * <p>
+     * All extensions should be added (ie, dicom, etc).
+     *
+     * @param ext          It is the extensions of files that should be indexed.
+     * <b>empty</b> string means that documents without extension will be indexed.
+     * 
+     * @see   IndexEngine
+     */
+    public void addExtension(String ext)
+    {
+        this.extensionsAllowed.add(ext);
+    }
+
+
+
+    @Override
+    public HashSet<String> getExtensionsAllowed()
+    {
+        return extensionsAllowed;
+    }
+
+    /**
+     * @return the maxMessages
+     */
+    @Override
+    public int getMaxMessages() {
+        return maxMessages;
+    }
+
+    /**
+     * @param maxMessages the maxMessages to set
+     */
+    public void setMaxMessages(int maxMessages) {
+        this.maxMessages = maxMessages;
+    }
+
+    @Override
+	public boolean isWANModeEnabled() {
+		// TODO Auto-generated method stub
+		return wanmode;
+	}
+
+	public void setWanmode(boolean wanmode) {
+		this.wanmode = wanmode;
+	}
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/TagsXML.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/TagsXML.java
new file mode 100755
index 0000000..4f1718c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/TagsXML.java
@@ -0,0 +1,379 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import org.slf4j.LoggerFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class TagsXML extends DefaultHandler
+{
+
+    private TagsStruct tags = TagsStruct.getInstance() ;
+
+
+    private boolean isTags = false ;
+    private boolean isDIM = false ;
+    private boolean isTag = false ;
+
+
+    private String tagTemp  = null ;
+    private String vr  = null ;
+    private String tagAliasTemp = null ;
+
+    private String modalities = null ;
+    private String modalityID = null ;
+    private ArrayList<String> modalityList = new ArrayList<String>();
+
+
+    public TagsXML()
+    {
+
+    }
+
+
+    @Override
+    public void startElement( String uri, String localName, String qName,
+            Attributes attribs )
+    {
+
+
+
+        if (localName.equals("Tags"))
+        {
+            isTags = true ;
+        }
+        else if( localName.equals( "DIM" ) )
+        {
+            isDIM = true;
+        }
+        else if ( localName.equals("tag") )
+        {
+            isTag = true ;
+            this.tagTemp = this.resolveAttrib("id", attribs, localName);
+            this.tagAliasTemp = this.resolveAttrib("alias", attribs, localName);
+            this.vr = this.resolveAttrib("vr", attribs, localName);
+
+        }
+        else if ( localName.equals("others"))
+        {
+        }
+         else if ( localName.equals("modalities"))
+        {
+            this.modalities = this.resolveAttrib("enable", attribs, localName);
+            String indexAll = this.resolveAttrib("all", attribs, localName);
+            if (indexAll.equals("true"))
+            {
+                tags.enableIndexAllModalities(true);
+            }
+            else if (indexAll.equals("false"))
+            {
+                tags.enableIndexAllModalities(false);
+            }
+            else
+            {
+                tags.enableIndexAllModalities(false);
+            }
+
+
+
+        }
+         else if (localName.equals("modality"))
+         {
+
+            this.modalityID = this.resolveAttrib("id", attribs, localName);
+         }
+    }
+
+
+    @Override
+    public void endElement( String uri, String localName, String qName )
+    {
+
+        if (localName.equals("Tags"))
+        {
+            isTags = false ;
+        }
+        else if( localName.equals( "DIM" ) )
+        {
+            isDIM = false;
+        }
+        else if ( localName.equals("tag") )
+        {
+
+            /** Verify if it is a DIM Fields */
+            if (isDIM)
+            {
+                if (this.tagTemp!= null)
+                {
+                	tags.addDIMField(new TagValue(Integer.parseInt(this.tagTemp, 16),
+                            this.tagAliasTemp));
+                }
+            }
+            else /** Otherwise it will be inserted on OtherFields */
+            {
+              /** Verification if it a duplicate fields will be made in TagsStruct
+               And it is the reason it isn't verify outside the Module
+               */
+
+                TagValue v =new TagValue(Integer.parseInt(this.tagTemp, 16),
+                        this.tagAliasTemp);
+                v.setVR(vr);
+                tags.addPrivateField(v);
+            }
+            isTag = false;
+        }
+        else if ( localName.equals("others"))
+        {
+        }
+         else if ( localName.equals("modalities"))
+        {
+            if (modalities.equals("true"))
+            {
+                tags.removeAllModalities();
+                for(String modality : this.modalityList)
+                	tags.addModality(modality);
+            }
+            else
+            {
+                tags.removeAllModalities();
+            }
+
+        }
+         else if (localName.equals("modality") )
+         {
+            this.modalityList.add(this.modalityID);
+         }
+    }
+
+
+   @Override
+    public void characters( char[] data, int start, int length )
+    {
+         new String(data, start, length);
+
+
+         if ( isTags && isDIM && isTag)
+         {
+
+             //System.out.println(tag);
+             return;
+         }
+
+
+    }
+
+
+     private String resolveAttrib( String attr, Attributes attribs, String defaultValue) {
+         String tmp = attribs.getValue(attr);
+         return (tmp!=null)?(tmp):(defaultValue);
+     }
+
+
+    public TagsStruct getXML() throws FileNotFoundException, SAXException, IOException
+    {
+        try
+        {
+            File file = new File(Platform.homePath() + "tags.xml");
+            if (!file.exists())
+            {
+                printXML();
+                return tags;
+            }
+
+
+            // Never throws the exception cause file not exists so need try catch
+            InputSource src = new InputSource( new FileInputStream(file) );
+            XMLReader r = XMLReaderFactory.createXMLReader();
+            r.setContentHandler(this);
+            r.parse(src);
+            return tags;
+        }
+        catch (IOException ex)
+        {
+
+        }
+        catch (SAXException ex)
+        {
+
+        }
+        return null;
+    }
+
+    public void printXML()
+    {
+
+        FileOutputStream out = null;
+        try
+        {
+            out = new FileOutputStream(Platform.homePath() + "tags.xml");
+        } catch (FileNotFoundException ex)
+        {
+            LoggerFactory.getLogger(TagsXML.class).error(ex.getMessage(), ex);
+        }
+        PrintWriter pw = new PrintWriter(out);
+        StreamResult streamResult = new StreamResult(pw);
+        SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+        //      SAX2.0 ContentHandler.
+        TransformerHandler hd = null;
+        try
+        {
+            hd = tf.newTransformerHandler();
+        } catch (TransformerConfigurationException ex)
+        {
+            LoggerFactory.getLogger(TagsXML.class).error(ex.getMessage(), ex);
+        }
+        Transformer serializer = hd.getTransformer();
+        serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+        serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");
+        hd.setResult(streamResult);
+        try
+        {
+            hd.startDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(TagsXML.class).error(ex.getMessage(), ex);
+        }
+
+        TagsStruct t = TagsStruct.getInstance();
+        AttributesImpl atts = new AttributesImpl();
+        try
+        {
+            //String curTitle = String.valueOf(s.getPort());
+            //root element
+            hd.startElement("", "", "Tags", atts);
+
+            // DIM
+            hd.startElement("", "", "DIM", atts);
+
+            // tags
+            for(TagValue tag : t.getDIMFields()){            	 
+                 atts.addAttribute("", "", "id", "", tag.getTagID());
+                 atts.addAttribute("", "", "alias", "", tag.getAlias()) ;
+                 hd.startElement("", "", "tag", atts);
+                 atts.clear();
+                 hd.endElement("", "", "tag");            	
+            }
+            hd.endElement("", "", "DIM");
+
+
+
+            // Others
+            hd.startElement("", "", "others", atts);
+
+            // tags
+            for(TagValue tag : t.getPrivateFields())
+            {
+                atts.addAttribute("", "", "id", "", tag.getTagID());
+                atts.addAttribute("", "", "alias", "", tag.getAlias()) ;
+                atts.addAttribute("", "", "vr", "", tag.getVR()) ;
+                hd.startElement("", "", "tag", atts);
+                atts.clear();
+                hd.endElement("", "", "tag");
+            }
+            hd.endElement("", "", "others");
+
+            // Modalities
+            String enable = "false" ;
+            if (t.getModalities() != null)
+                enable = "true";
+            atts.clear();
+            atts.addAttribute("", "", "enable", "", enable);
+            String indexAllModalities = "false" ;
+            if (t.isIndexAllModalitiesEnabled())
+                indexAllModalities = "true";
+            atts.addAttribute("", "", "all", "",indexAllModalities );
+            hd.startElement("", "", "modalities", atts);
+
+            // tags
+           if (t.getModalities() != null){
+        	   for(String modality: t.getModalities()){
+                    atts.addAttribute("", "", "id", "", modality);
+                    hd.startElement("", "", "modality", atts);
+                    atts.clear();
+                    hd.endElement("", "", "modality");
+                }
+           }
+
+
+            hd.endElement("", "", "modalities");
+            
+            
+            hd.startElement("", "", "dictionaries", atts);
+
+
+            
+            
+            
+            
+
+            hd.endElement("", "", "dictionaries");
+            
+            
+            hd.endElement("", "", "Tags");
+
+
+            hd.endDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(TagsXML.class).error(ex.getMessage(), ex);
+        }
+        finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+
+            }
+        }
+
+
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/UnZip.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/UnZip.java
new file mode 100755
index 0000000..64c2a8d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/UnZip.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+package pt.ua.dicoogle.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import org.slf4j.LoggerFactory;
+import java.util.zip.Adler32;
+import java.util.zip.CheckedInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class UnZip
+{
+    final int BUFFER = 2048;
+
+    private String filePath = null;
+    private ZipInputStream zis = null;
+    private BufferedOutputStream dest = null;
+    private CheckedInputStream checksum = null;
+
+
+    public UnZip(String filePath)
+    {
+        this.filePath = filePath;
+    }
+
+    public void loadFile()
+    {
+
+        FileInputStream fis = null;
+        try
+        {
+            fis = new FileInputStream(this.filePath);
+        }
+        catch (FileNotFoundException ex) {
+            LoggerFactory.getLogger(UnZip.class).error(ex.getMessage(), ex);
+        }
+        checksum = new CheckedInputStream(fis, new Adler32());
+        
+        
+        zis = new ZipInputStream(new BufferedInputStream(checksum));
+
+      }
+        
+
+
+    public void decompress()
+    {
+
+
+        if (zis==null)
+            return;
+        
+        ZipEntry entry;
+        try {
+            while ((entry = zis.getNextEntry()) != null) {
+                System.out.println("Extracting: " + entry);
+                int count;
+                byte[] data = new byte[BUFFER];
+                // write the files to the disk
+                FileOutputStream fos = new FileOutputStream(entry.getName());
+                dest = new BufferedOutputStream(fos, BUFFER);
+                while ((count = zis.read(data, 0, BUFFER)) != -1) {
+                    dest.write(data, 0, count);
+                }
+                dest.flush();
+                dest.close();
+            }
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(UnZip.class).error(ex.getMessage(), ex);
+        }
+
+
+    }
+
+    public void close()
+    {
+
+        try
+        {
+            zis.close();
+        } catch (IOException ex)
+        {
+            LoggerFactory.getLogger(UnZip.class).error(ex.getMessage(), ex);
+        }
+        System.out.println("Checksum:"+checksum.getChecksum().getValue());
+
+
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/Version.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/Version.java
new file mode 100644
index 0000000..3e92e56
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/Version.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+
+import java.io.IOException;
+import java.net.URL;
+
+/**
+ * Created by bastiao on 23/09/15.
+ */
+public class Version {
+    
+    public Version()
+    {
+        
+        
+    }
+    
+    public String getVersion()
+    {
+        String version = "dev";
+        URL url = Resources.getResource("version.txt");
+        try {
+            version = Resources.toString(url, Charsets.UTF_8);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return version;
+
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLClientSupport.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLClientSupport.java
new file mode 100755
index 0000000..83bdf4c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLClientSupport.java
@@ -0,0 +1,288 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ */
+public class XMLClientSupport extends DefaultHandler {
+
+    private String filePath;
+
+    private ClientSettings cs;
+
+    private boolean isViewer = false;
+    private boolean isHost = false;
+    private boolean isPort = false;
+    private boolean isTempDir = false;
+    private boolean isUsername = false;
+    private boolean isPassword = false;
+    private boolean isAutoConnect = false;
+
+    public XMLClientSupport() {
+        filePath = Platform.homePath() + "clientConfig.xml";
+        
+        cs = ClientSettings.getInstance();
+    }
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attribs) {
+        if (localName.equals("ExternalViewer")) {
+            isViewer = true;
+        }
+        else if(localName.equals("DefaultServerHost")){
+            isHost = true;
+        }
+        else if(localName.equals("DefaultServerPort")){
+            isPort = true;
+        }
+        else if(localName.equals("DefaultUsername")){
+            isUsername = true;
+        }
+        else if(localName.equals("DefaultPassword")){
+            isPassword = true;
+        }
+        else if(localName.equals("TempFilesDir")){
+            isTempDir = true;
+        }
+        else if(localName.equals("AutoConnect")){
+            isAutoConnect = true;
+        }
+
+
+    }
+
+    @Override
+    public void endElement(String uri, String localName, String qName) {
+        if (localName.equals("ExternalViewer")) {
+            isViewer = false;
+        }
+        else if(localName.equals("DefaultServerHost")){
+            isHost = false;
+        }
+        else if(localName.equals("DefaultServerPort")){
+            isPort = false;
+        }
+        else if(localName.equals("DefaultUsername")){
+            isUsername = false;
+        }
+        else if(localName.equals("DefaultPassword")){
+            isPassword = false;
+        }
+        else if(localName.equals("TempFilesDir")){
+            isTempDir = false;
+        }
+        else if(localName.equals("AutoConnect")){
+            isAutoConnect = false;
+        }
+    }
+
+    @Override
+    public void characters(char[] data, int start, int length) {
+        if (isViewer) {
+            String sView = new String(data, start, length);
+            cs.setExtV(sView);
+            return;
+        }
+        if(isHost){
+            String sView = new String(data, start, length);
+            cs.setDefaultServerHost(sView);
+            return;
+        }
+        if(isPort){
+            String sPort = new String(data, start, length);
+            cs.setDefaultServerPort(Integer.parseInt(sPort));
+            return;
+        }
+        if(isUsername){
+            String sUsername = new String(data, start, length);
+            cs.setDefaultUserName(sUsername);
+            return;
+        }
+        if(isPassword){
+            String sPassword = new String(data, start, length);
+            cs.setDefaultPassword(sPassword);
+            return;
+        }
+        if(isTempDir){
+            String sDir = new String(data, start, length);
+            cs.setTempFilesDir(sDir);
+            return;
+        }
+        if(isAutoConnect)
+        {
+             String sView = new String(data, start, length);
+             boolean result = false;
+             if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+             cs.setAutoConnect(result);
+             return;
+         }
+    }
+
+    public ClientSettings getXML()
+    {
+        try
+        {
+            File file = new File(filePath);
+            if (!file.exists())
+            {
+                cs.setDefaultSettings();
+                printXML();
+                return cs;
+            }
+            InputSource src = new InputSource( new FileInputStream(file) );
+            XMLReader r = XMLReaderFactory.createXMLReader();
+            r.setContentHandler(this);
+            r.parse(src);
+            return cs;
+        }
+        catch (IOException ex)
+        {
+
+        }
+        catch (SAXException ex)
+        {
+
+        }
+        return null;
+    }
+
+    public void printXML() {
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(filePath);
+            PrintWriter pw = new PrintWriter(out);
+            StreamResult streamResult = new StreamResult(pw);
+            SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+            //      SAX2.0 ContentHandler.
+            TransformerHandler hd = tf.newTransformerHandler();
+            Transformer serializer = hd.getTransformer();
+            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+            serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");
+            hd.setResult(streamResult);
+            hd.startDocument();
+
+            //Get a processing instruction
+            //hd.processingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"mystyle.xsl\"");
+            AttributesImpl atts = new AttributesImpl();
+
+            String curTitle;
+
+            //root element
+            hd.startElement("", "", "Config", atts);  
+
+            hd.startElement("", "", "DirectorySettings", atts);
+
+            curTitle = cs.getExtV();
+            //external viewer
+            hd.startElement("", "", "ExternalViewer", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "ExternalViewer");
+
+
+            curTitle = cs.getTempFilesDir();
+            //external viewer
+            hd.startElement("", "", "TempFilesDir", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "TempFilesDir");
+
+            hd.endElement("", "", "DirectorySettings");
+
+            hd.startElement("", "", "DefaultGUIServer", atts);
+
+            curTitle = cs.getDefaultServerHost();
+            //external viewer
+            hd.startElement("", "", "DefaultServerHost", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DefaultServerHost");
+
+            curTitle = String.valueOf(cs.getDefaultServerPort());
+            //external viewer
+            hd.startElement("", "", "DefaultServerPort", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DefaultServerPort");
+
+            curTitle = cs.getDefaultUserName();
+            //external viewer
+            hd.startElement("", "", "DefaultUsername", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DefaultUsername");
+
+            curTitle = cs.getDefaultPassword();
+            //external viewer
+            hd.startElement("", "", "DefaultPassword", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DefaultPassword");
+
+            if (cs.getAutoConnect())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable P2P
+            hd.startElement("", "", "AutoConnect", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "AutoConnect");
+
+            hd.endElement("", "", "DefaultGUIServer");
+
+            hd.endElement("", "", "Config");
+
+            hd.endDocument();
+
+        } catch (TransformerConfigurationException ex) {
+        } catch (SAXException ex) {
+        } catch (FileNotFoundException ex) {
+        } finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+            }
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLSupport.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLSupport.java
new file mode 100755
index 0000000..1aa5ba4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/XMLSupport.java
@@ -0,0 +1,1672 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.core;
+
+/**
+ * 
+ * @author Marco Pereira
+ * @modified Luís A. Bastião Silva <bastiao at ua.pt>
+ * @modified Samuel da Costa Campos <samuelcampos at ua.pt>
+ */
+
+
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.sdk.settings.types.ServerDirectoryPath;
+import pt.ua.dicoogle.server.*;
+
+import java.io.*;
+
+// SAX classes.
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+//JAXP 
+import javax.xml.transform.*;
+import javax.xml.transform.stream.*;
+import javax.xml.transform.sax.*;
+
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.swing.DefaultListModel;
+
+import org.xml.sax.XMLReader;
+import org.dcm4che2.data.UID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+public class XMLSupport extends DefaultHandler
+{
+    private static final Logger logger = LoggerFactory.getLogger(XMLSupport.class);
+    
+    private boolean isEncrypt = false;
+    private boolean isPort = false;
+    private boolean isRGUIPort = false;
+    private boolean isRGUIExtIP = false;
+    private boolean isIndexEffort = false;
+    private boolean isZIPFile = false;
+    private boolean isGZIPStorage = false;
+    private boolean isTS = false;    
+    private boolean isAET = false;
+    private boolean isCAET = false;
+    private boolean isPermitAllAETitles = false;
+    private boolean isPath = false;   
+    private boolean isDicoogleDir = false;
+    private boolean isFullContentIndex = false;
+    private boolean isSaveThumbnails = false;
+    private boolean isThumbnailsMatrix = false;
+    
+    private boolean isStorage = false;
+
+
+    /** P2P **/
+    private boolean isP2P = false ;
+    private boolean autoConnect = false ;
+    private boolean maxmsg = false;
+    private boolean isNode = false ;
+    private boolean isNodeName = false ; 
+    private boolean isDefined = false ;
+
+    /** 
+     * 
+     * Query Retreive Server configs
+     */ 
+    private boolean isQRConfigs = false ;
+    private boolean isDeviceDescription = false ; 
+    private boolean isLocalAETName = false ; 
+    private boolean isPermitedRemoteAETsNames = false ; 
+    private boolean isPermitedLocalInterfaces = false ; 
+    private boolean isPermitedRemoveHostnames = false ; 
+    private boolean isRspDelay = false ; 
+    private boolean isDIMSERspTimeout = false ; 
+    private boolean isIdleTimeout = false ; 
+    private boolean isAcceptTimeout = false ; 
+    private boolean isConnectTimeout = false ; 
+    private boolean isTransfCap = false ; 
+    private boolean isSOPClass = false ;
+    private boolean QREnable = false;
+    private boolean isMaxClientAssoc = false ; 
+    private boolean isMaxPDULengthReceive = false ; 
+    private boolean isMaxPDULengthSend = false ;
+
+    private boolean isWeb = false ;
+
+    private boolean isMonitorWatcher = false;
+
+    private boolean options = false ;
+    private boolean modality = false ;
+    private boolean cfind = false ;
+    private boolean find = false ;
+
+
+    private String sopId = null;
+
+    private boolean destinations = false ;
+    private boolean dest = false ;
+
+    private int port = 0 ;
+    private String AETitle = null ;
+    private String IP = null ;
+    private String description;
+    private String isPublic;
+
+    private boolean priorityAET = false;
+
+
+    private String currentService;
+    
+    private SOPList list;
+    private ServerSettings s;
+    private TransfersStorage LocalTS;
+    public TransfersStorage getLocalTS() {
+		return LocalTS;
+	}
+
+	private DefaultListModel m;
+    
+    
+    private boolean isIndexAnonymous = false;
+	private boolean isWANModeEnabled = false;
+    
+    
+    
+    public XMLSupport()
+    {        
+        list = SOPList.getInstance();
+        s = ServerSettings.getInstance();
+        LocalTS = new TransfersStorage();
+        m = new DefaultListModel();
+    }
+    
+    @Override
+    public void startElement( String uri, String localName, String qName, Attributes attribs )
+    {
+        if (localName.equals("QueryRetrieve"))
+        {
+            isQRConfigs = true ;
+        }else if(localName.equals("WANModeEnabled"))
+        {
+            isWANModeEnabled = true;
+        }
+        else if(localName.equals("EncryptUsersFile"))
+        {
+            isEncrypt = true;
+        }
+        else if(localName.equals( "IndexEffort" )){
+            isIndexEffort = true;
+        }
+        else if( localName.equals( "Port" ) && !isQRConfigs  )
+        {
+            isPort = true;            
+        }
+        else if( localName.equals( "IndexAnonymous" )  )
+        {
+            isIndexAnonymous = true;
+        }
+        else if( localName.equals( "IndexZipFiles" )  )
+        {
+            isZIPFile = true;
+        }
+        else if( localName.equals( "GZipStorage" )  )
+        {
+            isGZIPStorage = true;
+        }
+        else if( localName.equals( "MonitorWatcher" ) )
+        {
+            isMonitorWatcher = true ;
+        }    
+        else if( localName.equals( "P2P" ) && !isQRConfigs  )
+        {
+            isP2P = true;
+        }
+        else if( localName.equals( "AutoConnect" ) && isP2P  )
+        {
+            autoConnect = true ;
+        }
+        else if( localName.equals( "MaxMsg" ) && isP2P  )
+        {
+            maxmsg = true ;
+        }
+        else if( localName.equals( "Node" ) && isP2P  )
+        {
+            isNode = true ;
+        }
+        else if( localName.equals( "name" ) && isP2P  && isNode)
+        {
+            isNodeName = true ;
+        }
+        else if( localName.equals( "defined" ) && isP2P  && isNode)
+        {
+            isDefined = true ;
+        }
+
+        else if( localName.equals( "Storage" ))
+        {
+            isStorage = true;
+        }
+        else if( localName.equals( "DicoogleDir" ) )
+        {
+            isDicoogleDir = true;            
+        }
+        else if(localName.equals("fullContentIndex"))
+        {
+            isFullContentIndex = true;            
+        }    
+        else if(localName.equals("SaveThumbnails"))
+        {
+            isSaveThumbnails = true;            
+        }        
+        else if(localName.equals("ThumbnailsMatrix"))
+        {
+            isThumbnailsMatrix = true;            
+        }
+        else if(localName.equals("AETitle"))
+        {
+            isAET = true;
+        }
+        else if(localName.equals("CAETitle"))
+        {
+            isCAET = true;
+        }
+        else if(localName.equals("PermitAllAETitles"))
+        {
+            isPermitAllAETitles = true;
+        }
+        else if(localName.equals("Path"))
+        {
+            isPath = true;
+        }
+        else if(localName.equals("Service"))
+        {
+            currentService = resolveAttrib(uri, localName, attribs, UID.VerificationSOPClass);            
+        }
+        else if(localName.equals("TS"))
+        {
+            isTS = true;            
+        } 
+        /** Now Worklist Server parsing */ 
+        else if (localName.equals("DeviceDescription"))
+        {
+            isDeviceDescription = true;
+        }
+        else if (localName.equals("LocalAETName"))
+        {
+            isLocalAETName = true ; 
+        }
+        else if (localName.equals("PermitedRemoteAETsNames"))
+        {
+            isPermitedRemoteAETsNames = true ; 
+        }
+        else if (localName.equals("Port") && isQRConfigs)
+        {
+            isPort = true ; 
+        }
+        else if (localName.equals("PermitedLocalInterfaces"))
+        {
+            isPermitedLocalInterfaces = true ; 
+        }
+        else if (localName.equals("PermitedRemoveHostnames"))
+        {
+            isPermitedRemoveHostnames = true ; 
+        }
+        else if (localName.equals("RspDelay"))
+        {
+            isRspDelay = true ;
+        }
+        else if (localName.equals("DIMSERspTimeout"))
+        {
+            isDIMSERspTimeout = true ; 
+        }
+        else if (localName.equals("IdleTimeout"))
+        {
+            isIdleTimeout = true ; 
+        }        
+        else if (localName.equals("AcceptTimeout"))
+        {
+            isAcceptTimeout = true ; 
+        }
+        else if (localName.equals("ConnectionTimeout"))
+        {
+            isConnectTimeout = true ; 
+        }
+        else if (localName.equals("SOPClass"))
+        {
+            isSOPClass = true ; 
+        }
+        else if (localName.equals("QREnable"))
+        {
+            QREnable = true ;
+        }
+        else if (localName.equals("MAX_CLIENT_ASSOCS"))
+        {
+            isMaxClientAssoc = true ; 
+        }
+        else if (localName.equals("MAX_PDU_LENGTH_RECEIVE"))
+        {
+            isMaxPDULengthReceive = true ; 
+        }
+        else if (localName.equals("MAX_PDU_LENGTH_SEND"))
+        {
+            isMaxPDULengthSend = true ; 
+        }
+
+        if (localName.equals("options"))
+        {
+            this.options = true ;
+        }
+        else if (localName.equals("modality") && this.options)
+        {
+            this.modality = true ;
+        }
+        else if (localName.equals("cfind") && this.options && this.modality)
+        {
+            this.cfind = true ;
+        }
+        else if (localName.equals("find") && this.options && this.modality &&
+                this.cfind)
+        {
+            this.find = true ;
+            sopId = resolveAttrib(uri, localName, attribs, localName);
+
+        }
+
+        else if(localName.equals("destinations"))
+        {
+            this.destinations = true ;
+        }
+
+        else if (destinations && localName.equals("dest"))
+        {
+            this.dest  = true ;
+            this.AETitle = this.resolveAttrib("ae", attribs, localName);
+            this.port = Integer.parseInt(this.resolveAttrib("port", attribs, localName));
+            this.IP = this.resolveAttrib("ip", attribs, localName);
+            this.description = this.resolveAttrib("description", attribs, "");
+            this.isPublic = this.resolveAttrib("public", attribs, "false");
+
+            MoveDestination tmp = new MoveDestination(this.AETitle, this.IP,
+                    this.port, this.isPublic.contains("true"), this.description);
+            s.add(tmp);
+        }
+
+        else if(localName.equals("CSTOREPriorities"))
+        {
+            this.priorityAET = true ;
+        }
+        else if (priorityAET && localName.equals("aetitle"))
+        {
+            String aet = this.resolveAttrib("aetitle", attribs, localName);
+            //ServerSettings.getInstance().addPriorityAETitle(aet);
+        }
+
+
+        else if (localName.equals("web"))
+        {
+            this.isWeb = true ; 
+        }
+        else if (localName.equals("server") && this.isWeb)
+        {
+            String tmp = "";
+            ServerSettings.Web web = ServerSettings.getInstance().getWeb() ;
+            tmp = this.resolveAttrib("enable", attribs, localName);
+            web.setWebServer(Boolean.parseBoolean(tmp));
+            int port = Integer.valueOf(this.resolveAttrib("port", attribs, localName));
+            web.setServerPort(port);
+
+            String allowedOrigins = this.resolveAttrib("allowedOrigins", attribs, "");
+            web.setAllowedOrigins(allowedOrigins);
+        }
+
+        else if (localName.equals("services") && this.isWeb)
+        {
+            String tmp = "";
+            ServerSettings.Web web = ServerSettings.getInstance().getWeb() ;
+            tmp = this.resolveAttrib("enable", attribs, localName);
+            if (tmp.equals("true"))
+            {
+                web.setWebServices(true);
+            }
+            else
+            {
+                web.setWebServices(false);
+            }
+            int port = Integer.valueOf(this.resolveAttrib("port", attribs, localName));
+            web.setServicePort(port);
+
+
+
+        }
+        else if( localName.equals("RGUIPort") )
+        {
+            isRGUIPort = true;
+        }
+        else if(localName.equals("RGUIExtIP"))
+        {
+            isRGUIExtIP = true;
+        }
+
+
+
+     }
+     
+    @Override
+     public void endElement( String uri, String localName, String qName ) {
+        
+        if (localName.equals("QueryRetrieve"))
+        {
+            isQRConfigs = false ;
+        }else if(localName.equals("WANModeEnabled"))
+        {
+            isWANModeEnabled = false;
+        }
+        else if(localName.equals("EncryptUsersFile"))
+        {
+            isEncrypt = false;
+        }
+        else if( localName.equals( "Port" ) )
+        {
+            isPort = false;            
+        }
+        else if(localName.equals( "IndexEffort" )){
+            isIndexEffort = false;
+        }
+                
+        else if( localName.equals( "IndexAnonymous" )  )
+        {
+            isIndexAnonymous = false;
+        }
+                
+        else if( localName.equals( "IndexZipFiles" ) )
+        {
+            isZIPFile = false ;
+        }
+        else if( localName.equals( "GZipStorage" )  )
+        {
+            isGZIPStorage = false;
+        }
+        else if( localName.equals( "MonitorWatcher" ) )
+        {
+            isMonitorWatcher = false ;
+        }        
+                
+        else if( localName.equals( "P2P" ) )
+        {
+            isP2P = false;
+        }
+        else if( localName.equals( "AutoConnect" ) && isP2P  )
+        {
+            autoConnect = false ;
+        }
+        else if( localName.equals( "MaxMsg" ) && isP2P  )
+        {
+            maxmsg = false ;
+        }
+        else if( localName.equals( "Node" ) && isP2P  )
+        {
+            isNode = false ;
+        }
+        else if( localName.equals( "name" ) && isP2P  && isNode)
+        {
+            isNodeName = false ;
+        }
+        else if( localName.equals( "defined" ) && isP2P  && isNode)
+        {
+            isDefined = false ;
+        }
+
+
+        else if( localName.equals( "Storage" ) )
+        {
+            isStorage = false;
+        }
+        else if( localName.equals( "DicoogleDir" ) )
+        {
+            isDicoogleDir = false;            
+        }
+        else if( localName.equals( "fullContentIndex" ) )
+        {
+            isFullContentIndex = false;            
+        }        
+        else if( localName.equals( "SaveThumbnails" ) )
+        {
+            isSaveThumbnails = false;            
+        }          
+        else if( localName.equals( "ThumbnailsMatrix" ) )
+        {
+            isThumbnailsMatrix = false;            
+        }  
+        else if(localName.equals("AETitle"))
+        {
+            isAET = false;
+        }
+        else if(localName.equals("CAETitle"))
+        {
+            isCAET = false;
+        }
+        else if(localName.equals("PermitAllAETitles"))
+        {
+            isPermitAllAETitles = false;
+        }
+        else if(localName.equals("Path"))
+        {
+            isPath = false;
+        }        
+        else if(localName.equals("TS"))
+        {
+            isTS = false;            
+        }
+        if(localName.equals("Service"))
+        {             
+            list.updateTS(currentService, LocalTS.getTS(), true);
+        }
+        
+        /** Worklist Server */
+        if (localName.equals("DeviceDescription"))
+        {
+            isDeviceDescription = false ; 
+        }
+        else if (localName.equals("LocalAETName"))
+        {
+            isLocalAETName = false ; 
+        }
+        else if (localName.equals("PermitedRemoveAETsNames"))
+        {
+            isPermitedRemoteAETsNames = false ; 
+        }
+        else if (localName.equals("PermitedLocalInterfaces"))
+        {
+           isPermitedLocalInterfaces = false ;
+        }
+        else if (localName.equals("PermitedRemoveHostnames"))
+        {
+            isPermitedRemoveHostnames = false ; 
+        }
+        else if (localName.equals("RspDelay"))
+        {
+            isRspDelay = false ; 
+        }
+        else if (localName.equals("DIMSERspTimeout"))
+        {
+            isDIMSERspTimeout = false ; 
+        }
+        else if (localName.equals("IdleTimeout"))
+        {
+            isIdleTimeout = false ; 
+        }
+        else if (localName.equals("AcceptTimeout"))
+        {
+            isAcceptTimeout = false ; 
+        }
+        else if (localName.equals("ConnectionTimeout"))
+        {
+            isConnectTimeout = false ; 
+        }
+        else if (localName.equals("SOPClass"))
+        {
+            isSOPClass = false ; 
+        }
+        else if (localName.equals("QREnable"))
+        {
+            QREnable = false ;
+        }
+        else if (localName.equals("MAX_CLIENT_ASSOCS"))
+        {
+            isMaxClientAssoc = false ; 
+        }
+        else if (localName.equals("MAX_PDU_LENGTH_RECEIVE"))
+        {
+            isMaxPDULengthReceive = false ; 
+        }
+        else if (localName.equals("MAX_PDU_LENGTH_SEND"))
+        {
+            isMaxPDULengthSend = false; 
+        }
+        if (localName.equals("options"))
+        {
+            this.options = false ;
+        }
+        else if (localName.equals("modality") && this.options)
+        {
+            this.modality = false ;
+        }
+        else if (localName.equals("cfind") && this.options && this.modality)
+        {
+            this.cfind = false ;
+        }
+        else if (localName.equals("find") && this.options && this.modality &&
+                this.cfind)
+        {
+            this.find = false ;
+        }
+
+        else if(this.options && this.destinations && localName.equals("dest"))
+        {
+            this.dest = false  ;
+        }
+
+        else if (this.options && localName.equals("destinations"))
+        {
+            this.destinations = false ;
+        }
+
+        else if (this.priorityAET && localName.equals("CSTOREPriorities"))
+        {
+            this.priorityAET = false ;
+        }
+
+
+
+        else if (isWeb && localName.equals("web"))
+        {
+            this.isWeb = false ;
+        }
+        else if(isRGUIPort && localName.equals("RGUIPort") )
+        {
+            isRGUIPort = false;
+        }
+        else if(localName.equals("RGUIExtIP"))
+        {
+            isRGUIExtIP = false;
+        }
+
+
+     }
+     
+    @Override
+    public void characters( char[] data, int start, int length ) {
+        if (isIndexEffort) {
+            String sEffort = new String(data, start, length);
+            s.setIndexerEffort(Integer.parseInt(sEffort));
+            return;
+        }
+        if (isPort && !isQRConfigs) {
+            String sPort = new String(data, start, length);
+            s.setStoragePort(Integer.parseInt(sPort));
+            return;
+        }
+        if (isPort && isQRConfigs) {
+            String sPort = new String(data, start, length);
+            s.setWlsPort(Integer.parseInt(sPort));
+            return;
+        }
+        if (isEncrypt) {
+            String sView = new String(data, start, length);
+            boolean result = false;
+
+            if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+
+            s.setEncryptUsersFile(result);
+            return;
+        }
+
+
+        if (isZIPFile) {
+            String sView = new String(data, start, length);
+            boolean result = false;
+            if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+            s.setIndexZIPFiles(result);
+            return;
+        }
+
+        if (isGZIPStorage) {
+            String sView = new String(data, start, length);
+            boolean result = false;
+            if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+            s.setGzipStorage(result);
+            return;
+
+        }
+
+        if (isIndexAnonymous) {
+            String sView = new String(data, start, length);
+            boolean result = false;
+            if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+            s.setIndexAnonymous(result);
+            return;
+        }
+
+        if (isMonitorWatcher) {
+            String sView = new String(data, start, length);
+            boolean result = false;
+            if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+            s.setMonitorWatcher(result);
+            return;
+        }
+        if (isP2P) {
+
+            if (autoConnect) {
+                String sView = new String(data, start, length);
+                boolean result = false;
+                if (sView.compareToIgnoreCase("true") == 0)
+                    result = true;
+//                 s.setP2P(result);
+                return;
+
+            } else if (maxmsg) {
+                String max = new String(data, start, length);
+
+
+                int maxMsg = Integer.valueOf(max);
+                s.setMaxMessages(maxMsg);
+                return;
+
+            } else if (isNode && isNodeName) {
+                String nodeName = new String(data, start, length);
+                s.setNodeName(nodeName);
+            } else if (isNode && isDefined) {
+                String tmp = new String(data, start, length);
+                boolean result = false;
+                if (tmp.compareToIgnoreCase("true") == 0)
+                    result = true;
+                s.setNodeNameDefined(result);
+                return;
+            }
+        }
+
+        if (priorityAET)
+        {
+            String aetitle = new String(data, start, length);
+            s.addPriorityAETitle(aetitle);
+            return;
+
+        }
+
+         if(isStorage)
+         {
+             String sView = new String(data, start, length);
+             boolean result = false;
+             if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+             s.setStorage(result);
+             return;
+         }
+         if(isDicoogleDir) //( "DicoogleDir" ) )
+         {
+             String sView = new String(data, start, length);
+             s.setDicoogleDir(sView);
+             return;           
+         } 
+         if(isFullContentIndex) 
+         {
+             String sView = new String(data, start, length);
+             boolean result = false;
+             if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+             s.setFullContentIndex(result);
+             return;           
+         }     
+         if(isSaveThumbnails)
+         {
+             String sView = new String(data, start, length);
+             boolean result = false;
+             if (sView.compareToIgnoreCase("true") == 0)
+                result = true;
+             s.setSaveThumbnails(result);
+             return;           
+         }         
+         if(isThumbnailsMatrix) 
+         {
+             String sView = new String(data, start, length);
+             s.setThumbnailsMatrix(sView);
+             return;              
+         }
+         if(isAET)
+         { 
+             String sAET = new String(data, start, length);
+             if(sAET.equals(" "))
+             {                
+                s.setAE(null);
+             }
+             else
+             {
+                s.setAE(sAET);
+             }
+             return;
+         }
+         if(isCAET)
+         { 
+             String sCAET = new String(data, start, length);             
+             m.addElement(sCAET);
+             String [] CAET = new String[m.getSize()];
+             m.copyInto(CAET);
+             s.setCAET(CAET);
+             return;
+         }
+         if(isPermitAllAETitles){
+            String sPermit = new String(data, start, length);
+             boolean result = false;
+             if (sPermit.compareToIgnoreCase("true") == 0)
+                result = true;
+             s.setPermitAllAETitles(result);
+             return;
+         }
+         if(isPath)
+         { 
+             String sPath = new String(data, start, length);
+             if(sPath.equals(" "))
+             {
+                s.setPath(".");
+             }
+             else
+             {
+                s.setPath(sPath);
+             }
+             return;
+         }
+         if(isTS)
+         {
+            String sTS = new String(data, start, length);
+            if(UID.ImplicitVRLittleEndian.equals(sTS))
+            {
+                    LocalTS.setTS(true, 0);                    
+                    return;
+            }
+            if(UID.ExplicitVRLittleEndian.equals(sTS))
+            {
+                    LocalTS.setTS(true, 1);
+                    return;
+            }
+            if(UID.DeflatedExplicitVRLittleEndian.equals(sTS))
+            {
+                    LocalTS.setTS(true, 2);
+                    return;
+            }              
+            if(UID.ExplicitVRBigEndian.equals(sTS))
+            {
+                    LocalTS.setTS(true, 3);
+                    return;
+            }
+            if(UID.JPEGLossless.equals(sTS))
+            {
+                    LocalTS.setTS(true, 4);
+                    return;
+            }
+            if(UID.JPEGLSLossless.equals(sTS))
+            {
+                    LocalTS.setTS(true, 5);
+                    return;
+            }
+            if(UID.JPEGLosslessNonHierarchical14.equals(sTS))
+            {
+                    LocalTS.setTS(true, 6);
+                    return;
+            }
+            if(UID.JPEG2000LosslessOnly.equals(sTS))
+            {
+                    LocalTS.setTS(true, 7);
+                    return;
+            }
+            if(UID.JPEGBaseline1.equals(sTS))
+            {
+                    LocalTS.setTS(true, 8);
+                    return;
+            }
+            if(UID.JPEGExtended24.equals(sTS))
+            {
+                    LocalTS.setTS(true, 9);
+                    return;
+            }
+            if(UID.JPEGLSLossyNearLossless.equals(sTS))
+            {
+                    LocalTS.setTS(true, 10);
+                    return;
+            }
+            if(UID.JPEG2000.equals(sTS))
+            {
+                    LocalTS.setTS(true, 11);
+                    return;
+            }
+            if(UID.RLELossless.equals(sTS))
+            {
+                    LocalTS.setTS(true, 12);
+                    return;
+            }
+            if(UID.MPEG2.equals(sTS))
+            {
+                    LocalTS.setTS(true, 13);
+                    return;
+            }
+         }
+
+         /** QueryRetrieve Server */
+         if (isQRConfigs && QREnable)
+         {
+             String tmp = new String(data, start, length);
+             if(tmp.equals("true")){
+                 s.setQueryRetrive(true);
+             }
+             else{
+                s.setQueryRetrive(false);
+                //DebugManager.getInstance().debug("QueryRetrieve service is disable by default");
+             }
+             return;
+
+         }
+         if (isQRConfigs && isSOPClass)
+         {
+             String tmp = new String(data, start, length);
+             return;
+         }
+         if (isQRConfigs && isTransfCap)
+         {
+            return;
+         }
+         
+        if (isQRConfigs && options && modality && cfind )
+        {
+            if (find)
+            {
+                String sop = new String(data, start, length);
+
+                s.addModalityFind(sopId, sop.trim());
+                return ;
+            }
+
+        }
+        if (isQRConfigs && options && destinations)
+        {
+            return;
+
+
+        }
+        if(isMaxClientAssoc){
+            String sNumber = new String(data, start, length);
+            s.setMaxClientAssoc(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isMaxPDULengthReceive){
+            String sNumber = new String(data, start, length);
+            s.setMaxPDULengthReceive(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isMaxPDULengthSend){
+            String sNumber = new String(data, start, length);
+            s.setMaxPDULengthSend(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isRspDelay){
+            String sNumber = new String(data, start, length);
+            s.setRspDelay(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isIdleTimeout){
+            String sNumber = new String(data, start, length);
+            s.setIdleTimeout(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isAcceptTimeout){
+            String sNumber = new String(data, start, length);
+            s.setAcceptTimeout(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isConnectTimeout){
+            String sNumber = new String(data, start, length);
+            s.setConnectionTimeout(Integer.parseInt(sNumber));
+            return;
+        }
+        if(isRGUIPort){
+            String sPort = new String(data, start, length);
+            s.setRemoteGUIPort(Integer.parseInt(sPort));
+            return;
+        }
+        if(isRGUIExtIP){
+            String sPort = new String(data, start, length);
+            s.setRGUIExternalIP(sPort);
+            return;
+        }
+        if(isWANModeEnabled){
+            String a = new String(data, start, length);
+            boolean b = Boolean.parseBoolean(a);
+            s.setWanmode(b);
+            return;
+        }
+         
+     }
+
+
+     
+     private String resolveAttrib( String attr, Attributes attribs, String defaultValue)
+     {
+
+         String tmp = attribs.getValue(attr);
+
+
+
+         return (tmp!=null)?(tmp):(defaultValue);
+     }
+
+
+     private String resolveAttrib( String uri, String localName, Attributes attribs, String defaultValue) {
+         String tmp = attribs.getValue("UID"); 
+         return (tmp!=null)?(tmp):(defaultValue);
+     } 
+     
+     /** 
+      * Worklist Server - Verify if qr is enable
+      * @param uri
+      * @param localName
+      * @param attribs
+      * @param defaultValue
+      * @return
+      */
+     private boolean getStatus( String uri, String localName, Attributes attribs, String defaultValue) {
+         String tmp = attribs.getValue("state"); 
+         return (tmp!=null && tmp.equals("on"))?(true):(false);
+     } 
+     
+     
+  
+    public ServerSettings getXML()
+    {        
+        try 
+        {
+            File file = new File(Platform.homePath() + "config.xml");
+            if (!file.exists())
+            {   
+                s.setDefaultSettings();
+                list.setDefaultSettings();                
+                printXML();
+                return s;
+            }
+            InputSource src = new InputSource( new FileInputStream(file) );
+            XMLReader r = XMLReaderFactory.createXMLReader();
+            r.setContentHandler(this);
+            r.parse(src);
+            return s;
+        }
+        catch (IOException | SAXException ex)
+        {
+            logger.warn("Failed to read XML config file", ex);
+        }        
+        return null;
+    }
+    
+    public void printXML()
+    {
+        FileOutputStream out = null;
+        list.CleanList();
+        try {
+            out = new FileOutputStream(Platform.homePath() + "config.xml");
+            PrintWriter pw = new PrintWriter(out);
+            StreamResult streamResult = new StreamResult(pw);
+            SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+            //      SAX2.0 ContentHandler.
+            TransformerHandler hd = tf.newTransformerHandler();
+            Transformer serializer = hd.getTransformer();
+            serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");            
+            serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+            serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");            
+            hd.setResult(streamResult);
+            hd.startDocument();
+            
+            //Get a processing instruction
+            //hd.processingInstruction("xml-stylesheet", "type=\"text/xsl\" href=\"mystyle.xsl\"");
+            AttributesImpl atts = new AttributesImpl();
+            
+            //root element
+            hd.startElement("", "", "Config", atts);            
+
+
+            String curTitle = String.valueOf(s.getStoragePort());
+            //port            
+            hd.startElement("", "", "Port", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "Port");
+
+            atts.clear();
+            hd.startElement("", "", "RemoteGUI", atts);
+
+            curTitle = String.valueOf(s.getRemoteGUIPort());
+            //GUIport
+            hd.startElement("", "", "RGUIPort", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "RGUIPort");
+
+
+            curTitle = s.getRGUIExternalIP();
+            if(curTitle != null && !curTitle.equals(""))
+            {
+                hd.startElement("", "", "RGUIExtIP", atts);
+                hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+                hd.endElement("", "", "RGUIExtIP");
+            }
+            hd.endElement("", "", "RemoteGUI");
+            
+            
+            curTitle = s.getPath();
+            //path          
+            hd.startElement("", "", "Path", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "Path");
+
+            curTitle = String.valueOf(s.getIndexerEffort());
+            //path
+            hd.startElement("", "", "IndexEffort", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "IndexEffort");
+
+            hd.startElement("", "", "IndexZipFiles", atts);
+
+            if (s.isIndexZIPFiles())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable IndexZipFiles
+
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            hd.endElement("", "", "IndexZipFiles");
+            
+            
+            
+            hd.startElement("", "", "GZipStorage", atts);
+
+            if (s.isGzipStorage())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable IndexZipFiles
+
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            hd.endElement("", "", "GZipStorage");
+            
+            
+            
+            
+
+            hd.startElement("", "", "IndexAnonymous", atts);
+
+            if (s.isIndexAnonymous())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable IndexZipFiles
+
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            hd.endElement("", "", "IndexAnonymous");
+            
+            hd.startElement("", "", "MonitorWatcher", atts);
+            if (s.isMonitorWatcher())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable IndexZipFiles
+
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            hd.endElement("", "", "MonitorWatcher");
+            
+            
+
+            hd.startElement("", "", "EncryptUsersFile", atts);
+            if (s.isEncryptUsersFile())
+                curTitle = "true";
+            else
+                curTitle = "false";
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "EncryptUsersFile");
+
+            if (s.isWANModeEnabled())
+                curTitle = "true";
+            else
+                curTitle = "false";
+            hd.startElement("", "", "WANModeEnabled", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "WANModeEnabled");
+            
+            hd.startElement("", "", "P2P", atts);
+            
+            hd.startElement("", "", "AutoConnect", atts);
+
+/*            if (s.isP2P())
+                curTitle = "true";
+            else
+                curTitle = "false";*/
+
+            //Enable P2P
+            
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            
+            hd.endElement("", "", "AutoConnect");
+
+            hd.startElement("", "", "MaxMsg", atts);
+            curTitle = String.valueOf(s.getMaxMessages());
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            hd.endElement("", "", "MaxMsg");
+
+            hd.startElement("", "", "Node", atts);
+
+            hd.startElement("", "", "name", atts);
+            hd.characters(s.getNodeName().toCharArray(), 0, s.getNodeName().length());
+            hd.endElement("", "", "name");
+
+            if (s.isNodeNameDefined())
+                curTitle = "true";
+            else
+                curTitle = "false";
+            hd.startElement("", "", "defined", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "defined");
+
+
+            hd.endElement("", "", "Node");
+
+
+            hd.endElement("", "", "P2P");
+
+            if (s.isStorage())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable P2P
+            hd.startElement("", "", "Storage", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "Storage");
+
+            curTitle = s.getDicoogleDir();
+            //Diccogle Scan Dir           
+            hd.startElement("", "", "DicoogleDir", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DicoogleDir");
+            
+            
+            curTitle = Boolean.toString(s.getFullContentIndex());
+            // FullContentIndex           
+            hd.startElement("", "", "fullContentIndex", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "fullContentIndex");
+
+            curTitle = Boolean.toString(s.getSaveThumbnails());
+            // saveThumbnails           
+            hd.startElement("", "", "SaveThumbnails", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "SaveThumbnails");
+
+            curTitle = s.getThumbnailsMatrix();
+            // saveThumbnails           
+            hd.startElement("", "", "ThumbnailsMatrix", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "ThumbnailsMatrix");
+            
+            curTitle = s.getAE();
+            //AET
+            hd.startElement("", "", "AETitle", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "AETitle");
+
+
+            if (s.getPermitAllAETitles())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable P2P
+            hd.startElement("", "", "PermitAllAETitles", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "PermitAllAETitles");
+
+            //Permited Client AETitles
+            String [] CAET = s.getCAET();
+            if(CAET!= null)
+            {
+                for(int i=0; i<CAET.length; i++)
+                {
+                    curTitle = CAET[i];
+                    hd.startElement("", "", "CAETitle", atts);
+                    hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+                    hd.endElement("", "", "CAETitle");
+                }
+            }
+            
+            
+            List l = list.getKeys();
+            boolean [] TS;
+            int i = l.size()-1;
+            for(i = l.size()-1; i >= 0; i--)
+            {
+               
+               LocalTS = list.getTS(l.get(i).toString());
+               if(LocalTS.getAccepted())
+               {
+                    atts.addAttribute("", "", "UID", "", l.get(i).toString());            
+                    hd.startElement("", "", "Service", atts);
+                    atts.clear();
+                    TS = LocalTS.getTS();
+                    if(TS[0])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.ImplicitVRLittleEndian.toCharArray(), 0, UID.ImplicitVRLittleEndian.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[1])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.ExplicitVRLittleEndian.toCharArray(), 0, UID.ExplicitVRLittleEndian.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[2])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.DeflatedExplicitVRLittleEndian.toCharArray(), 0, UID.DeflatedExplicitVRLittleEndian.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[3])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.ExplicitVRBigEndian.toCharArray(), 0, UID.ExplicitVRBigEndian.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[4])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGLossless.toCharArray(), 0, UID.JPEGLossless.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[5])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGLSLossless.toCharArray(), 0, UID.JPEGLSLossless.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[6])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGLosslessNonHierarchical14.toCharArray(), 0, UID.JPEGLosslessNonHierarchical14.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[7])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEG2000LosslessOnly.toCharArray(), 0, UID.JPEG2000LosslessOnly.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[8])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGBaseline1.toCharArray(), 0, UID.JPEGBaseline1.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[9])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGExtended24.toCharArray(), 0, UID.JPEGExtended24.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[10])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEGLSLossyNearLossless.toCharArray(), 0, UID.JPEGLSLossyNearLossless.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[11])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.JPEG2000.toCharArray(), 0, UID.JPEG2000.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[12])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.RLELossless.toCharArray(), 0, UID.RLELossless.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    if(TS[13])
+                    {
+                        hd.startElement("", "", "TS",atts);
+                        hd.characters(UID.MPEG2.toCharArray(), 0, UID.MPEG2.length());
+                        hd.endElement("", "", "TS");
+                    }
+                    hd.endElement("", "", "Service");
+
+
+               }
+            }
+
+
+            // LocalAETName
+            curTitle = s.getLocalAETName();
+            hd.startElement("", "", "LocalAETName", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "LocalAETName");
+
+
+
+             /**
+               * Query Retrieve stuff
+             */
+            
+            //Query Retrieve
+            hd.startElement("", "", "QueryRetrieve", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+
+            curTitle = s.getDeviceDescription();
+            // Device Description
+            curTitle = s.getDeviceDescription();
+            hd.startElement("", "", "DeviceDescription", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DeviceDescription");
+
+            if (s.isQueryRetrive())
+                curTitle = "true";
+            else
+                curTitle = "false";
+
+            //Enable QueryRetrieve by default
+            hd.startElement("", "", "QREnable", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "QREnable");
+
+            // Port
+            curTitle = Integer.toString(s.getWlsPort());
+            hd.startElement("", "", "Port", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "Port");
+
+            // Permited Local Interfaces
+            curTitle = s.getPermitedLocalInterfaces();
+            hd.startElement("", "", "PermitedLocalInterfaces", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "PermitedLocalInterfaces");
+
+            curTitle = s.getPermitedRemoteHostnames();
+            hd.startElement("", "", "PermitedHostnames", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "PermitedHostnames");
+
+            curTitle = Integer.toString(s.getRspDelay());
+            hd.startElement("", "", "RspDelay", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "RspDelay");
+
+            curTitle = Integer.toString(s.getDIMSERspTimeout());
+            hd.startElement("", "", "DIMSERspTimeout", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "DIMSERspTimeout");
+
+            curTitle = Integer.toString(s.getIdleTimeout());
+            hd.startElement("", "", "IdleTimeout", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "IdleTimeout");
+
+            curTitle = Integer.toString(s.getAcceptTimeout());
+            hd.startElement("", "", "AcceptTimeout", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "AcceptTimeout");
+
+            curTitle = Integer.toString(s.getConnectionTimeout());
+            hd.startElement("", "", "ConnectionTimeout", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "ConnectionTimeout");
+
+            curTitle = s.getTransfCap();
+            hd.startElement("", "", "TRANSF_CAP", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "TRANSF_CAP");
+
+            curTitle = s.getSOPClass() ; 
+            hd.startElement("", "", "SOP_CLASS", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "SOP_CLASS");
+
+            curTitle = Integer.toString(s.getMaxClientAssoc());
+            hd.startElement("", "", "MAX_CLIENT_ASSOCS", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "MAX_CLIENT_ASSOCS");
+
+            curTitle = Integer.toString(s.getMaxPDULengthReceive());
+            hd.startElement("", "", "MAX_PDU_LENGTH_RECEIVE", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "MAX_PDU_LENGTH_RECEIVE");
+
+            curTitle = Integer.toString(s.getMaxPDULenghtSend());
+            hd.startElement("", "", "MAX_PDU_LENGTH_SEND", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "MAX_PDU_LENGTH_SEND");
+
+
+            hd.startElement("", "", "Retrieve", atts);
+
+            curTitle = s.getSOPClass();
+            hd.startElement("", "", "SOPClass", atts);
+            hd.characters(curTitle.toCharArray(), 0, curTitle.length());
+            hd.endElement("", "", "SOPClass");
+
+
+            hd.endElement("", "", "Retrieve");
+
+
+            //root element
+            hd.startElement("", "", "options", atts);
+
+            //modality
+            hd.startElement("", "", "modality", atts);
+
+
+
+            // cfind
+            hd.startElement("", "", "cfind", atts);
+
+            HashMap<String, String> map = s.getModalityFind();
+            for (String sop : map.keySet())
+            {
+                atts.addAttribute("", "", "sop", "", sop);
+                hd.startElement("", "", "find", atts);
+                atts.clear();
+                String tmp = map.get(sop);
+                hd.characters(tmp.toCharArray(), 0, tmp.length());
+                hd.endElement("", "", "find");
+            }
+            hd.endElement("", "", "cfind");
+
+
+            hd.endElement("", "", "modality");
+
+
+            // destinations
+
+            hd.startElement("", "", "destinations", atts);
+
+
+            ArrayList<MoveDestination> moves = s.getMoves();
+            for (MoveDestination m : moves)
+            {
+
+                atts.clear();
+                atts.addAttribute("", "", "ae", "", m.getAETitle());
+                atts.addAttribute("", "", "ip", "", m.getIpAddrs());
+                atts.addAttribute("", "", "description", "", m.getDescription());
+                atts.addAttribute("", "", "public", "",Boolean.toString(m.isIsPublic()));
+
+                atts.addAttribute("", "", "port", "", String.valueOf(m.getPort()));
+
+                hd.startElement("", "", "dest", atts);
+
+                hd.endElement("", "", "dest");
+                atts.clear();
+            }
+
+
+            hd.endElement("", "", "destinations");
+
+
+            // CSTOREPriorities
+
+            hd.startElement("", "", "CSTOREPriorities", atts);
+
+            for (String aet : ServerSettings.getInstance().getPriorityAETitles())
+            {
+                atts.clear();
+                hd.startElement("", "", "aetitle", atts);
+                hd.characters(aet.toCharArray(), 0, aet.length());
+                hd.endElement("", "", "aetitle");
+            }
+
+            hd.endElement("", "", "CSTOREPriorities");
+
+
+
+
+            hd.endElement("", "", "options");
+
+            hd.endElement("", "", "QueryRetrieve");
+
+
+            /**
+             * Web (including web server, webservices, etc)
+             */
+
+            hd.startElement("", "", "web", atts);
+
+
+            ServerSettings.Web web = ServerSettings.getInstance().getWeb() ;
+
+            // WebServer
+
+            String tmp = "false";
+            if (web.isWebServer())
+                tmp = "true";
+
+            atts.clear();
+            atts.addAttribute("", "", "enable", "", tmp);
+            atts.addAttribute("", "", "port", "", String.valueOf(web.getServerPort()));
+            atts.addAttribute("", "", "allowedOrigins", "", web.getAllowedOrigins());
+
+            hd.startElement("", "", "server", atts);
+
+            hd.endElement("", "", "server");
+
+
+
+            // WebServices
+
+            tmp = "false";
+            if (web.isWebServices())
+                tmp = "true";
+
+            atts.clear();
+            atts.addAttribute("", "", "enable", "", tmp);
+            atts.addAttribute("", "", "port", "", String.valueOf(web.getServicePort()));
+
+            hd.startElement("", "", "services", atts);
+
+            hd.endElement("", "", "services");
+
+
+            hd.endElement("", "", "web");
+
+
+
+            hd.endElement("", "", "Config");
+            
+            hd.endDocument();
+                        
+        } catch (TransformerConfigurationException ex) {
+            
+        } catch (SAXException ex) {
+            
+        } catch (FileNotFoundException ex) {
+            
+        } finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+                
+            }
+        }
+   }
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/Zip.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/Zip.java
new file mode 100755
index 0000000..ad6d986
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/Zip.java
@@ -0,0 +1,208 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import org.slf4j.LoggerFactory;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class Zip implements Closeable
+{
+
+    static final int BUFFER = 2048;
+
+    private BufferedInputStream origin = null;
+    private ZipOutputStream out = null;
+
+    private String zipName = null;
+
+    private boolean createFile = false;
+
+    public Zip(String  zipName)
+    {
+        this.zipName = zipName;
+    }
+
+    public void createZip()
+    {
+
+        // just do it one-time.
+        if (createFile)
+            return;
+
+        ServerSettings ss = ServerSettings.getInstance() ;
+
+        try 
+        {
+            System.out.println("DIR: "+getZipName());
+            FileOutputStream dest = new FileOutputStream(getZipName());
+            
+             out = new ZipOutputStream(new 
+           BufferedOutputStream(dest));
+
+
+            //out.setMethod(ZipOutputStream.DEFLATED);
+            byte data[] = new byte[BUFFER];
+
+
+            createFile = true;
+            
+        
+        } 
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+
+    }
+
+
+    public void addFile(byte [] arr)
+    {
+
+        
+    }
+
+
+
+    public void addFile(String fullPath)
+    {
+
+        File file = new File(fullPath);
+        byte data[] = new byte[BUFFER];
+        FileInputStream fi = null;
+        try
+        {
+            fi = new FileInputStream(file);
+        } catch (FileNotFoundException ex) {
+            LoggerFactory.getLogger(Zip.class).error(ex.getMessage(), ex);
+        }
+        origin = new BufferedInputStream(fi, BUFFER);
+        ZipEntry entry = new ZipEntry(fullPath);
+        if (out==null)
+            System.err.println("OUT NULL");
+
+
+        if (entry==null)
+            System.err.println("entry NULL");
+
+        try
+        {
+            out.putNextEntry(entry);
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(Zip.class).error(ex.getMessage(), ex);
+        }
+        int count;
+        try {
+            while ((count = origin.read(data, 0, BUFFER)) != -1) {
+                out.write(data, 0, count);
+            }
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(Zip.class).error(ex.getMessage(), ex);
+        }
+        try {
+            origin.close();
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(Zip.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    public void close()
+    {
+        try {
+            out.close();
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(Zip.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    /**
+     * @return the createFile
+     */
+    public boolean isCreateFile() {
+        return createFile;
+    }
+
+    /**
+     * @param createFile the createFile to set
+     */
+    public void setCreateFile(boolean createFile) {
+        this.createFile = createFile;
+    }
+
+    /**
+     * @return the zipName
+     */
+    public String getZipName() {
+        return zipName;
+    }
+
+    /**
+     * @param zipName the zipName to set
+     */
+    public void setZipName(String zipName) {
+        this.zipName = zipName;
+    }
+
+    
+    
+    public static void main(String [] args)
+    {
+    
+    
+        long timeEncryptStart = System.currentTimeMillis();
+        Zip zip = new Zip("/Volumes/Extend/dataset/IM-0001-0001.zip");
+        zip.createZip();
+        zip.addFile("/Volumes/Extend/dataset/XABraga/IM-0001-0001.dcm");
+        
+        zip.close();
+                  
+            
+            long timeEncryptEnd = System.currentTimeMillis() - timeEncryptStart;
+            System.out.println("Encrypted in " + timeEncryptEnd + " (ms)");
+            
+            timeEncryptStart = System.currentTimeMillis();
+            
+            UnZip unzip = new UnZip("/Volumes/Extend/dataset/IM-0001-0001.zip");
+            unzip.loadFile();
+            unzip.decompress();
+            
+            timeEncryptEnd = System.currentTimeMillis() - timeEncryptStart;
+            System.out.println("Encrypted in " + timeEncryptEnd + " (ms)");
+            
+            
+    }
+    
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/PrivateDictionary.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/PrivateDictionary.java
new file mode 100755
index 0000000..8230fe8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/PrivateDictionary.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dicom;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ *
+ * @author bastiao
+ */
+public class PrivateDictionary 
+{
+
+    public void parse(String file)
+    {
+        String NL = System.getProperty("line.separator");
+        Scanner scanner = null;
+        try {
+            scanner = new Scanner(new FileInputStream(file));
+        } catch (FileNotFoundException ex) {
+            LoggerFactory.getLogger(PrivateDictionary.class).error(ex.getMessage(), ex);
+        }
+        try {
+            while (scanner.hasNextLine()) {
+                String text = scanner.nextLine();
+                String tag = ""; 
+                    
+                String type = "";
+                String name = ""; 
+                
+                
+                if (text.startsWith("(") )
+                {
+                    String txt[] = text.split(" |\t");
+
+                    for (int i = 0; i< txt.length; i++)
+                    {
+                        if (txt[i].startsWith("("))
+                        {
+                            tag = txt[i] ;
+                        }
+                        else if (txt[i].length()==2)
+                        {
+                            type = txt[i] ;
+                            name = txt[i+1] ;
+                        }
+                    }
+                }
+                if (!tag.equals("")&&!type.equals("")&&!name.equals(""))
+                {
+                    //System.out.println("Tag: "+tag);
+                    //System.out.println("Type: "+type);
+                    //System.out.println("Name: "+name);
+                    
+                    TagsStruct tg = TagsStruct.getInstance();
+                    tag = tag.replaceAll("\\(", "");
+                    tag = tag.replaceAll("\\)", "");
+                    tag = tag.replaceAll(" ", "");
+                    tag = tag.replaceAll(",", "");
+                    //System.out.println("Tag: "+tag);
+                    //System.out.println("Type: "+type);
+                    //System.out.println("Name: "+name);
+                    
+                    TagValue v = new TagValue(Integer.parseInt(tag, 16), name);
+                    
+                    v.setVR(type);
+                    tg.addPrivateField(v);
+                    
+                }
+            }
+        } finally {
+            scanner.close();
+        }
+    }
+    
+    public static void main(String [] args)
+    {
+        PrivateDictionary pd = new PrivateDictionary();
+        pd.parse("/Users/bastiao/MAP-I/Code/dicomlamedictionaryanddicom/similarity.dic");
+        
+    
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/SearchURI.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/SearchURI.java
new file mode 100644
index 0000000..c052d82
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dicom/SearchURI.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dicom;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author Luís A. Bastião Silva - <bastiao at ua.pt>
+ */
+public class SearchURI {
+
+    public Iterable<SearchResult> search(String query) {
+
+        HashMap<String, String> extraFields = new HashMap<String, String>();
+        ArrayList<SearchResult> resultsArr = new ArrayList<SearchResult>();
+        extraFields.put("SOPInstanceUID", "SOPInstanceUID");
+        MyHolder holder = new MyHolder();
+        PluginController.getInstance().queryAll(holder, query, extraFields);
+        Iterable<SearchResult> results = null;
+        try {
+            results = holder.get();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(SearchURI.class).error(ex.getMessage(), ex);
+        } catch (ExecutionException ex) {
+            LoggerFactory.getLogger(SearchURI.class).error(ex.getMessage(), ex);
+        }
+        if (results==null)
+        {
+            return results;
+        }
+        for (SearchResult r : results) {
+            resultsArr.add(r);
+        }
+
+        return resultsArr;
+        
+
+    }
+
+    class MyHolder extends JointQueryTask {
+
+        @Override
+        public void onCompletion() {
+            
+        }
+
+        @Override
+        public void onReceive(Task<Iterable<SearchResult>> e) {
+
+        }
+
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/ConcatTags.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/ConcatTags.java
new file mode 100644
index 0000000..1f1f6fb
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/ConcatTags.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.core.dim;
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+
+
+/**
+ *
+ * @author bastiao
+ */
+public class ConcatTags
+{
+
+    public static final String FILENAME=  "concatTags.conf";
+    private static final Logger logger = LoggerFactory.getLogger(ConcatTags.class);
+
+
+    /**
+     * @return the rules
+     */
+    public List<Rule> getRules() {
+        return rules;
+    }
+
+    /**
+     * @param rules the rules to set
+     */
+    public void setRules(List<Rule> rules) {
+        this.rules = rules;
+    }
+
+    public class Rule
+    {
+
+        private String modality;
+        private String tagToReplace;
+
+        /**
+         * @return the modality
+         */
+        public String getModality() {
+            return modality;
+        }
+
+        /**
+         * @param modality the modality to set
+         */
+        public void setModality(String modality) {
+            this.modality = modality;
+        }
+
+        /**
+         * @return the tagToReplace
+         */
+        public String getTagToReplace() {
+            return tagToReplace;
+        }
+
+        /**
+         * @param tagToReplace the tagToReplace to set
+         */
+        public void setTagToReplace(String tagToReplace) {
+            this.tagToReplace = tagToReplace;
+        }
+
+    }
+
+    private List<Rule> rules = new ArrayList<Rule>();
+
+
+    public void parseConfig(String file) throws FileNotFoundException
+    {
+
+        //StringBuilder text = new StringBuilder();
+        //String NL = System.getProperty("line.separator");
+        Scanner scanner = new Scanner(new FileInputStream(file));
+        try {
+            while (scanner.hasNextLine()){
+                String text = scanner.nextLine();
+                logger.info("Rule for: " + text);
+                Rule r = parseLine(text);
+                logger.info("Rule for: " + r.getModality());
+                if (r!=null)
+                {
+                    this.rules.add(r);
+                    logger.info("Rule added: " + r.getModality());
+                }
+            }
+        }
+        finally{
+            scanner.close();
+        }
+
+    }
+
+    // Sample: CR;StudyDescription;EMPTY;AquisitionDeviceProcessionDescription;StudyDescription==staff
+
+    public Rule parseLine(String line)
+    {
+        logger.info("Rule parse for: " + line);
+        if (line==null || line.equals(""))
+            return null;
+
+        Rule r = new Rule();
+        String [] tmp = line.split(";");
+        String modality = tmp[0];
+        String tag = tmp[3];
+        r.setModality(modality);
+        r.setTagToReplace(tag);
+        return r;
+
+
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/DIMGeneric.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/DIMGeneric.java
new file mode 100755
index 0000000..86c6d83
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/DIMGeneric.java
@@ -0,0 +1,556 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dim;
+
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.util.*;
+
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang3.StringUtils;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class DIMGeneric
+{
+    /**
+     * There are double space to save the results but it decrease
+     * the search time and it is important because a querySearch should be
+     * little enough.
+     */
+    private ArrayList<Patient> patients = new ArrayList<>();
+    private HashMap<String, Patient> patientsHash  = new HashMap<>();
+    
+    private static String toTrimmedString(Object o, boolean allowNull){
+    	if(o == null)
+    		if(allowNull)
+    			return null;
+    		else return "";
+    		
+    	if(allowNull)
+    		return StringUtils.trimToNull(o.toString());
+    	
+    	return StringUtils.trimToEmpty(o.toString());
+    }
+
+    private ConcatTags tags;
+
+    private static final Logger logger = LoggerFactory.getLogger(DIMGeneric.class);
+
+    public DIMGeneric(ConcatTags tags, Iterable<SearchResult> arr) throws Exception
+    {
+        this.tags = tags;
+        fill(arr, 4);
+
+    }
+
+    /**
+     * it is allow to handle a ArrayList of Strings or SearchResults
+     * @param arr
+     */
+    public DIMGeneric(Iterable<SearchResult> arr, int depth) throws Exception{
+        fill(arr, depth);
+    }
+
+    public DIMGeneric(Iterable<SearchResult> arr) throws Exception{
+        this(arr, 4);
+    }
+
+    /**
+     * it is allow to handle a ArrayList of Strings or SearchResults
+     * @param arr
+     */
+    private void fill(Iterable<SearchResult> arr, int depth) {
+            //DebugManager.getInstance().debug("Looking search results: " + arr.size() );
+
+            Map<String, String> descriptions = new HashMap<String, String>();
+
+            for(SearchResult r : arr){
+
+                /**
+                 * Looking for SearchResults and put it in right side :)
+                 */
+
+                //SearchResult r = (SearchResult) arr.get(i);
+                final HashMap<String, Object> extra = r.getExtraData();
+
+                /** Get data from Study */
+                final String studyUID = toTrimmedString(extra.get("StudyInstanceUID"),false);
+                final String modality = toTrimmedString( extra.get("Modality"), false);
+                final String patientID =  toTrimmedString( extra.get("PatientID"), false);
+                final String patientName =  toTrimmedString(extra.get("PatientName"), false);
+                String StudyDescription = toTrimmedString( extra.get("StudyDescription"), false);
+
+                /**
+                 * Get data to Image
+                 */
+                //TODO:Error checking here... but according to standard, all images
+                //must have one of these...
+                String sopInstUID =  toTrimmedString(extra.get("SOPInstanceUID"), true);
+                         
+                if(sopInstUID == null)
+                    sopInstUID ="no uid";
+
+                logger.debug("StudyDescription: {}", StudyDescription);
+                
+                // This is a quick fix for changing the parameters for the query.
+                if ((StudyDescription==null||StudyDescription.equals("")||StudyDescription.toLowerCase().contains("fuji"))
+                        &&
+                        this.tags!=null) {
+                    logger.debug("Checking if the Rule applies: {}", studyUID);
+                    String description = "";
+
+                    if (descriptions.containsKey(studyUID)) {
+                        description = descriptions.get(studyUID);
+                    }
+
+                    for (ConcatTags.Rule rule : this.tags.getRules())
+                    {
+                        logger.debug("Checking if the Rule applies: {}", modality);
+
+                        if (modality.equals(rule.getModality())) {
+                            String valueTagToReplace = (String) extra.get(rule.getTagToReplace());
+                            logger.debug("Checking if the Rule value. {}", valueTagToReplace);
+                            logger.debug("Checking if the Rule value. {}", rule.getTagToReplace());
+
+                            if (valueTagToReplace!=null)
+                            {
+                                // Required to production enviroment. I'm not changing to toTrimmedString until get a stable release.
+                                // complete ported.
+                                valueTagToReplace = valueTagToReplace.trim().replaceAll("[^a-zA-Z0-9\\. ÉéàÀÃ;,]+","");
+                                description = description + valueTagToReplace + "; ";
+                            }
+                        }
+
+                    }
+                    StudyDescription = description;
+                    descriptions.put(studyUID, StudyDescription);
+
+                }
+
+                String patientIdentifier = patientID;
+                if (patientID.equals("")) {
+                    patientIdentifier = patientName;
+                }
+
+                /** Verify if Patient already exists */
+
+                if (this.patientsHash.containsKey(patientIdentifier))
+                {
+                    if (depth >= 1) {
+                        /**
+                         * Patient Already exists, let's check studys
+                         */
+                        // Real data does not have Patient Id - sometimes.
+                        Patient p = this.patientsHash.get(patientIdentifier);
+
+                        Study s = this.fillStudy(p, extra, StudyDescription);
+                        if (depth > 2) {
+                            Serie serie = this.fillSeries(s, extra);
+                            if (depth > 3) {
+                                serie.addImage(r.getURI(), sopInstUID);
+                            }
+                        }
+                    }
+                }
+                else {
+                    /**
+                     * Patient does not exist
+                     */
+                    Patient p = new Patient(patientID, patientName);
+
+                    /* Get Patient Data */
+                    String patientSex = toTrimmedString(  extra.get("PatientSex"), false);
+                    p.setPatientSex(patientSex);
+
+                    String patientBirthDate = toTrimmedString(  extra.get("PatientBirthDate"), false);
+                    p.setPatientBirthDate(patientBirthDate);
+
+                    if (depth >= 1) {
+                        /**
+                         * Create Study
+                         */
+                        Study s = this.fillStudy(p, extra, StudyDescription);
+                        if (depth > 2) {
+                            Serie serie = this.fillSeries(s, extra);
+                            if (depth > 3) {
+                                serie.addImage(r.getURI(), sopInstUID);
+                            }
+                        }
+                    }
+                    this.patients.add(p);
+                    this.patientsHash.put(patientIdentifier, p);
+                }
+            }
+
+    }
+
+    /**
+     * Add Study
+     * It also verify if it exists
+     * In the last case Object will be discarded and the
+     * data will be added for the Study that already exists
+     */
+    public Study fillStudy(Patient parent, Map<String, Object> extra, String StudyDescription) {
+        /** Get data from Study */
+        String studyUID = toTrimmedString(extra.get("StudyInstanceUID"),false);
+        String studyID = toTrimmedString(extra.get("StudyID"), false);
+        String studyDate = toTrimmedString( extra.get("StudyDate"), false);
+        String studyTime = toTrimmedString( extra.get("StudyTime"), true);
+        String AccessionNumber = toTrimmedString( extra.get("AccessionNumber"), false);
+        String InstitutionName = toTrimmedString( extra.get("InstitutionName"), false);
+        String operatorsName = toTrimmedString (extra.get("OperatorsName"), false);
+        String RequestingPhysician = toTrimmedString (extra.get("RequestingPhysician"), false);
+
+        Study s = parent.getStudy(studyUID);
+        if (s == null) {
+            s = new Study(parent, studyUID, studyDate);
+            parent.addStudy(s);
+        }
+        s.setInstitutuionName(InstitutionName);
+        s.setAccessionNumber(AccessionNumber);
+        s.setStudyTime(studyTime);
+        s.setStudyID(studyID);
+        s.setStudyDescription(StudyDescription);
+        s.setPatientName(parent.getPatientName());
+        s.setOperatorsName(operatorsName);
+        s.setRequestingPhysician(RequestingPhysician);
+        return s;
+    }
+
+    public Serie fillSeries(Study parent, Map<String, Object> extra) {
+        String seriesUID =  toTrimmedString( extra.get("SeriesInstanceUID"), false);
+        String modality = toTrimmedString( extra.get("Modality"), false);
+        Serie s = parent.getSeries(seriesUID);
+        if (s == null) {
+            s = new Serie(parent, seriesUID, modality);
+            parent.addSerie(s);
+        }
+
+        String serieNumber = toTrimmedString(extra.get("SeriesNumber"), true);
+        if (serieNumber != null && !serieNumber.equals("")) {
+            s.setSerieNumber((int) Float.parseFloat(serieNumber));
+        }
+
+        String serieDescription = toTrimmedString(  extra.get("SeriesDescription"), false);
+        s.setSeriesDescription(serieDescription);
+
+        String SeriesDate =  toTrimmedString(extra.get("SeriesDate"), false);
+        s.setSeriesDate(SeriesDate);
+
+        String ProtocolName =  toTrimmedString(extra.get("ProtocolName"), false);
+        s.setProtocolName(ProtocolName);
+
+        String ViewPosition = toTrimmedString( extra.get("ViewPosition"), false);
+        s.setViewPosition(ViewPosition);
+
+        String ImageLaterality = toTrimmedString( extra.get("ImageLaterality"), false);
+        s.setImageLaterality(ImageLaterality);
+
+        String ViewCodeSequence_CodeValue =  toTrimmedString( extra.get("ViewCodeSequence_CodeValue"), false);
+        s.setViewCodeSequence_CodeValue(ViewCodeSequence_CodeValue);
+
+        String ViewCodeSequence_CodingSchemeDesignator =  toTrimmedString( extra.get("ViewCodeSequence_CodingSchemeDesignator"), false);
+        s.setViewCodeSequence_CodingSchemeDesignator(ViewCodeSequence_CodingSchemeDesignator);
+
+        String ViewCodeSequence_CodingSchemeVersion =  toTrimmedString( extra.get("ViewCodeSequence_CodingSchemeVersion"), false);
+        s.setViewCodeSequence_CodingSchemeVersion(ViewCodeSequence_CodingSchemeVersion);
+
+        String ViewCodeSequence_CodeMeaning =  toTrimmedString( extra.get("ViewCodeSequence_CodeMeaning"), false);
+        s.setViewCodeSequence_CodeMeaning(ViewCodeSequence_CodeMeaning);
+
+        String AcquisitionDeviceProcessingDescription = toTrimmedString( extra.get("AcquisitionDeviceProcessingDescription"), false);
+        s.setAcquisitionDeviceProcessingDescription(AcquisitionDeviceProcessingDescription);
+
+        return s;
+    }
+
+    public void writeJSON(Writer destinationWriter, long elapsedTime) throws IOException {
+        this.writeJSON(destinationWriter, elapsedTime, 4, 0, Integer.MAX_VALUE);
+    }
+
+    public void writeJSON(Writer destinationWriter, long elapsedTime, int depth, int offset, int psize) throws IOException {
+        JSONWriter writer = new JSONWriter(destinationWriter);
+        try {
+            writer.object()
+                    .key("numResults").value(this.patients.size());
+            if (depth > 0) {
+                writer.key("results").array();
+
+                for (Patient p : this.patients) {
+                    if (offset-- > 0) continue;
+
+                    writer.object()
+                            .key("id").value(p.getPatientID())
+                            .key("name").value(p.getPatientName())
+                            .key("gender").value(p.getPatientSex())
+                            .key("birthdate").value(p.getPatientBirthDate())
+                            .key("nStudies").value(p.getStudies().size());
+
+                    if (depth > 1) {
+                        writer.key("studies").array(); // begin studies
+
+                        for (Study study : p.getStudies()) {
+                            writer.object()    // begin study
+                                    .key("studyInstanceUID").value(study.getStudyInstanceUID())
+                                    .key("studyDescription").value(study.getStudyDescription())
+                                    .key("studyDate").value(study.getStudyData())
+                                    .key("institutionName").value(study.getInstitutuionName())
+                                    //.key("nSeries").value(study.getSeries().size())
+                            ;
+                            Set<String> modalities = new HashSet<>();
+
+                            if (depth > 2) {
+                                writer.key("series").array(); // begin series (array)
+                                for (Serie series : study.getSeries()) {
+                                    String modality = series.getModality();
+                                    int nimages = series.getSOPInstanceUIDList().size();
+                                    writer.object() // begin series
+                                            .key("serieNumber").value(series.getSerieNumber())
+                                            .key("serieInstanceUID").value(series.getSerieInstanceUID())
+                                            .key("serieDescription").value(series.getSeriesDescription())
+                                            .key("serieModality").value(modality)
+                                            //.key("nImages").value(nimages)
+                                    ;
+                                    if (depth > 3) {
+                                        writer.key("images").array(); // begin images
+                                        for (int i = 0; i < nimages; i++) {
+                                            String rawPath = series.getImageList().get(i).getRawPath();
+                                            writer.object() // begin image
+                                                    .key("sopInstanceUID").value(series.getSOPInstanceUIDList().get(i))
+                                                    .key("rawPath").value(rawPath)
+                                                    .key("uri").value(series.getImageList().get(i).toString())
+                                                    .key("filename").value(rawPath.substring(rawPath.lastIndexOf("/")+1, rawPath.length()))
+                                                    .endObject(); // end image
+                                        }
+                                        writer.endArray(); // end images
+                                    }
+
+                                    modalities.add(modality);
+                                    writer.endObject(); // end series
+                                }
+                                writer.endArray(); // end series (array)
+                                writer.key("modalities");
+                                if (modalities.size() == 1) {
+                                    writer.value(modalities.iterator().next());
+                                } else {
+                                    writer.array(); // begin modalities in study
+                                    for (String m : modalities) {
+                                        writer.value(m);
+                                    }
+                                    writer.endArray(); // end modalities in study
+                                }
+                            }
+                            writer.endObject(); // end study
+                        }
+                        writer.endArray(); // end studies
+                    }
+                    writer.endObject(); // end patient
+                    if (--psize <= 0) break;
+                }
+                writer.endArray(); // end patients
+            }
+            writer
+                    .key("elapsedTime").value(elapsedTime)
+                    .endObject(); // end output
+        } catch (JSONException e) {
+            throw new IOException("JSON serialization error", e);
+        }
+    }
+
+    public String getJSON(){
+    	JSONObject result = new JSONObject();
+    	result.put("numResults", this.patients.size());
+    	JSONArray patients = new JSONArray();
+    	
+    	for (Patient p : this.patients){
+    		JSONObject patient = new JSONObject();
+    		patient.put("id", p.getPatientID());
+    		patient.put("name", p.getPatientName());
+    		patient.put("gender", p.getPatientSex());
+    		patient.put("nStudies", p.getStudies().size());
+    		patient.put("birthdate", p.getPatientBirthDate());
+    		
+    		JSONArray studies = new JSONArray();
+    		for(Study s: p.getStudies())
+    		{
+    			JSONObject study = new JSONObject();
+    			study.put("studyDate", s.getStudyData());
+    			study.put("studyDescription", s.getStudyDescription());
+    			study.put("studyInstanceUID", s.getStudyInstanceUID());
+    			study.put("institutionName", s.getInstitutuionName());
+    			
+    			JSONArray modalities = new JSONArray();
+    			JSONArray series = new JSONArray();
+    			
+    			Set<String> modalitiesSet = new HashSet<>();
+    			for(Serie serie : s.getSeries())
+    			{
+    				modalitiesSet.add(serie.getModality());
+    				modalities.add(serie.getModality());
+    				
+    				JSONObject _serie = new JSONObject();
+    				_serie.put("serieNumber", serie.getSerieNumber());
+    				_serie.put("serieInstanceUID", serie.getSerieInstanceUID());
+    				_serie.put("serieDescription", serie.getSeriesDescription());
+    				_serie.put("serieModality", serie.getModality());
+    				
+    				JSONArray _sopInstanceUID = new JSONArray();
+    				for(int i=0; i<serie.getSOPInstanceUIDList().size();i++){
+    					JSONObject image = new JSONObject();
+    					image.put("sopInstanceUID", serie.getSOPInstanceUIDList().get(i));
+    					String rawPath = serie.getImageList().get(i).getRawPath();
+    					image.put("rawPath", rawPath);    					
+    					image.put("uri", serie.getImageList().get(i).toString());
+                        image.put("filename", rawPath.substring(rawPath.lastIndexOf("/")+1, rawPath.length()));
+    					
+    					_sopInstanceUID.add(image);
+    				}
+    				_serie.put("images", _sopInstanceUID);
+    
+    				series.add(_serie);
+    			}
+    			study.put("modalities", StringUtils.join(modalitiesSet,","));
+    			study.put("series", series);
+    			
+    			
+    			
+    			
+    			studies.add(study);
+    			
+    		}
+    		patient.put("studies", studies);
+    		
+    		
+    		patients.add(patient);
+    	}
+    	
+    	result.put("results", patients);
+    	
+    	return result.toString();
+    }
+    
+    public String getXML()
+    {
+
+        StringWriter writer = new StringWriter();
+
+
+        StreamResult streamResult = new StreamResult(writer);
+        SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+        //      SAX2.0 ContentHandler.
+        TransformerHandler hd = null;
+        try {
+            hd = tf.newTransformerHandler();
+        } catch (TransformerConfigurationException ex) {
+            LoggerFactory.getLogger(DIMGeneric.class).error(ex.getMessage(), ex);
+        }
+        Transformer serializer = hd.getTransformer();
+        serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+        serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");
+        hd.setResult(streamResult);
+        try {
+            hd.startDocument();
+
+            AttributesImpl atts = new AttributesImpl();
+            hd.startElement("", "", "DIM", atts);
+
+            for (Patient p : this.patients)
+            {
+                atts.clear();
+                atts.addAttribute("", "", "name", "",p.getPatientName().trim());
+                atts.addAttribute("", "", "id", "",p.getPatientID().trim());
+                hd.startElement("", "", "Patient", atts);
+
+
+                for (Study s: p.getStudies())
+                {
+                    atts.clear();
+                    atts.addAttribute("", "", "date", "",s.getStudyData().trim());
+                    atts.addAttribute("", "", "id", "", s.getStudyInstanceUID().trim());
+
+                    hd.startElement("", "", "Study", atts);
+
+                    for (Serie serie : s.getSeries()){
+                        atts.clear();
+                        atts.addAttribute("", "", "modality", "", serie.getModality().trim());
+                        atts.addAttribute("", "", "id", "", serie.getSerieInstanceUID().trim());
+
+                        hd.startElement("", "", "Serie", atts);
+
+                        ArrayList<URI> img = serie.getImageList();
+                        ArrayList<String> uid = serie.getSOPInstanceUIDList();
+                        int size = img.size();
+                        for (int i=0;i<size;i++){
+                            atts.clear();
+                            atts.addAttribute("", "", "path", "", img.get(i).toString().trim());
+                            atts.addAttribute("", "", "uid", "", uid.get(i).trim());
+
+                            hd.startElement("", "", "Image", atts);
+                            hd.endElement("", "", "Image");
+                        }
+                        hd.endElement("", "", "Serie");
+                    }
+                    hd.endElement("", "", "Study");
+                }
+                hd.endElement("", "", "Patient");
+            }
+            hd.endElement("", "", "DIM");
+
+        } catch (SAXException ex) {
+            LoggerFactory.getLogger(DIMGeneric.class.getName()).error(ex.getMessage(), ex);
+        }
+
+        return writer.toString() ;
+    }
+
+    /**
+     * @return the patients
+     */
+    public ArrayList<Patient> getPatients() {
+        return patients;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Patient.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Patient.java
new file mode 100755
index 0000000..7bea99a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Patient.java
@@ -0,0 +1,169 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dim;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class Patient
+{
+    private String PatientID;
+    private String PatientName;
+    private String PatientSex;
+    private String PatientBirthDate;
+
+    private ArrayList<Study> studies = new ArrayList<>() ;
+    private Map<String, Study> studiesHash = new HashMap<>();
+    private int nStudyOverride = -1;
+
+    public Patient(String PatientID, String PatientName)
+    {
+        this.PatientName = PatientName;
+        this.PatientID = PatientID;
+    }
+
+    public Patient(String PatientID)
+    {
+        this.PatientID = PatientID;
+    }
+
+    /**
+     * Add new Study to Patient
+     * @param s
+     */
+    public void addStudy(Study s)
+    {
+
+        if (this.studiesHash.containsKey(s.getStudyInstanceUID()))
+        {
+            /** 
+             * The study exists, so it will take the series and add the series
+             */
+
+            Study es = this.studiesHash.get(s.getStudyInstanceUID()) ;
+            es.setStudyDescription(s.getStudyDescription());
+            for (Serie e: s.getSeries())
+            {
+                es.addSerie(e);
+            }
+           
+        }
+        else
+        {
+            this.getStudies().add(s);
+            this.studiesHash.put(s.getStudyInstanceUID(), s);
+        }
+
+    }
+
+    /**
+     * Get the Study with StudyInstanceUID. If it exists
+     * will be returned. Otherwise a null is returned
+     * @return s Stydy Result
+     */
+    public Study getStudy(String studyInstanceUID)
+    {
+        return this.studiesHash.get(studyInstanceUID);
+    }
+
+
+    public String toString()
+    {
+        String result = "";
+        result += "PatientID: " + this.getPatientID() ;
+        if (this.getPatientName()!=null)
+            result = "PatientName: " + this.getPatientName() + "\n";
+        if (this.getPatientSex() != null)
+            result = "PatientSax: " + this.getPatientSex() + "\n";
+        
+        // XXX Study + Series 
+
+        return result ; 
+    }
+
+    /**
+     * @return the PatientID
+     */
+    public String getPatientID() {
+        return PatientID;
+    }
+
+    /**
+     * @param PatientID the PatientID to set
+     */
+    public void setPatientID(String PatientID) {
+        this.PatientID = PatientID;
+    }
+
+    /**
+     * @return the PatientName
+     */
+    public String getPatientName() {
+        return PatientName;
+    }
+
+    /**
+     * @param PatientName the PatientName to set
+     */
+    public void setPatientName(String PatientName) {
+        this.PatientName = PatientName;
+    }
+
+    /**
+     * @return the PatientSex
+     */
+    public String getPatientSex() {
+        return PatientSex;
+    }
+
+    /**
+     * @param PatientSex the PatientSex to set
+     */
+    public void setPatientSex(String PatientSex) {
+        this.PatientSex = PatientSex;
+    }
+
+    /**
+     * @return the studies
+     */
+    public ArrayList<Study> getStudies() {
+        return studies;
+    }
+
+    /**
+     * @return the PatientBirthDate
+     */
+    public String getPatientBirthDate() {
+        return PatientBirthDate;
+    }
+
+    /**
+     * @param PatientBirthDate the PatientBirthDate to set
+     */
+    public void setPatientBirthDate(String PatientBirthDate) {
+        this.PatientBirthDate = PatientBirthDate;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Serie.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Serie.java
new file mode 100755
index 0000000..9acac95
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Serie.java
@@ -0,0 +1,374 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dim;
+
+import java.net.URI;
+import java.util.ArrayList;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class Serie
+{
+
+    private Study parent;
+    private String SerieInstanceUID ;
+    private String SeriesDescription;
+
+    private int SerieNumber ;
+    private String Modality ;
+    private String SeriesDate = "";
+    private String ProtocolName = "";
+
+    private String BodyPartThickness = "";
+    private String patientOrientation = "";
+    private String compressionForce = "";
+    // Only for MG
+    private String ViewCodeSequence = "";
+    private String ViewCodeSequence_CodeValue = "";
+    private String ViewCodeSequence_CodingSchemeDesignator = "";
+    private String ViewCodeSequence_CodingSchemeVersion = "";
+    private String ViewCodeSequence_CodeMeaning = "";
+
+    private String ViewPosition = "";
+    private String ImageLaterality = "";
+    private String AcquisitionDeviceProcessingDescription = "";
+    
+    
+    private ArrayList<URI> imageList = new ArrayList<>();
+    private ArrayList<String> UIDList = new ArrayList<>();
+
+    public Serie(Study study, String SerieInstanceUID, String modality)
+    {
+        this.parent = study;
+        this.Modality = modality;
+        this.SerieInstanceUID = SerieInstanceUID ; 
+        
+    }
+
+    public Serie(Study study, String SerieInstanceUID, int SerieNumber)
+    {
+        this.parent = study;
+        this.SerieInstanceUID = SerieInstanceUID ;
+        this.SerieNumber = SerieNumber ; 
+        
+    }
+
+
+    public void addImage(URI ImagePath, String sopUid){
+        this.imageList.add(ImagePath);
+        this.UIDList.add(sopUid);
+    }
+
+    public void removeImage(URI imagePath){
+        this.imageList.remove(imagePath);
+    }
+
+
+    /**
+     * @return the SerieInstanceUID
+     */
+    public String getSerieInstanceUID(){
+        return SerieInstanceUID;
+    }
+
+    /**
+     * @param SerieInstanceUID the SerieInstanceUID to set
+     */
+    public void setSerieInstanceUID(String SerieInstanceUID) {
+        this.SerieInstanceUID = SerieInstanceUID;
+    }
+
+    /**
+     * @return the SerieNumber
+     */
+    public int getSerieNumber() {
+        return SerieNumber;
+    }
+
+    /**
+     * @param SerieNumber the SerieNumber to set
+     */
+    public void setSerieNumber(int SerieNumber) {
+        this.SerieNumber = SerieNumber;
+    }
+
+    /**
+     * @return the imageList
+     */
+    public ArrayList<URI> getImageList() {
+        return imageList;
+    }
+
+    public ArrayList<String> getSOPInstanceUIDList(){
+        return UIDList;
+    }
+
+    /**
+     * @param imageList the imageList to set
+     */
+    public void setImageList(ArrayList<URI> imageList, ArrayList<String> sops) {
+        this.imageList = imageList;
+        this.UIDList = sops;
+    }
+
+    /**
+     * @return the Modality
+     */
+    public String getModality() {
+        return Modality;
+    }
+
+    /**
+     * @param Modality the Modality to set
+     */
+    public void setModality(String Modality) {
+        this.Modality = Modality;
+    }
+
+    /**
+     * @return the parent
+     */
+    public Study getParent() {
+        return parent;
+    }
+
+    /**
+     * @param parent the parent to set
+     */
+    public void setParent(Study parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * @return the SeriesDescription
+     */
+    public String getSeriesDescription() {
+        return SeriesDescription;
+    }
+
+    /**
+     * @param SeriesDescription the SeriesDescription to set
+     */
+    public void setSeriesDescription(String SeriesDescription) {
+        this.SeriesDescription = SeriesDescription;
+    }
+
+
+    /**
+     * @return the SeriesDate
+     */
+    public String getSeriesDate() {
+        return SeriesDate;
+    }
+
+    /**
+     * @param SeriesDate the SeriesDate to set
+     */
+    public void setSeriesDate(String SeriesDate) {
+        this.SeriesDate = SeriesDate;
+    }
+
+
+
+    /**
+     * @return the ProtocolName
+     */
+    public String getProtocolName() {
+        return ProtocolName;
+    }
+
+    /**
+     * @param ProtocolName the ProtocolName to set
+     */
+    public void setProtocolName(String ProtocolName) {
+        this.ProtocolName = ProtocolName;
+    }
+
+    /**
+     * @return the BodyPartThickness
+     */
+    public String getBodyPartThickness() {
+        return BodyPartThickness;
+    }
+
+    /**
+     * @param BodyPartThickness the BodyPartThickness to set
+     */
+    public void setBodyPartThickness(String BodyPartThickness) {
+        this.BodyPartThickness = BodyPartThickness;
+    }
+
+
+    /**
+     * @return the patientOrientation
+     */
+    public String getPatientOrientation() {
+        return patientOrientation;
+    }
+
+    /**
+     * @param patientOrientation the patientOrientation to set
+     */
+    public void setPatientOrientation(String patientOrientation) {
+        this.patientOrientation = patientOrientation;
+    }
+
+    /**
+     * @return the compressionForce
+     */
+    public String getCompressionForce() {
+        return compressionForce;
+    }
+
+    /**
+     * @param compressionForce the compressionForce to set
+     */
+    public void setCompressionForce(String compressionForce) {
+        this.compressionForce = compressionForce;
+    }
+
+    /**
+     * @return the ViewCodeSequence
+     */
+    public String getViewCodeSequence() {
+        return ViewCodeSequence;
+    }
+
+    /**
+     * @param ViewCodeSequence the ViewCodeSequence to set
+     */
+    public void setViewCodeSequence(String ViewCodeSequence) {
+        this.ViewCodeSequence = ViewCodeSequence;
+    }
+
+    /**
+     * @return the ViewCodeSequence_CodeValue
+     */
+    public String getViewCodeSequence_CodeValue() {
+        return ViewCodeSequence_CodeValue;
+    }
+
+    /**
+     * @param ViewCodeSequence_CodeValue the ViewCodeSequence_CodeValue to set
+     */
+    public void setViewCodeSequence_CodeValue(String ViewCodeSequence_CodeValue) {
+        this.ViewCodeSequence_CodeValue = ViewCodeSequence_CodeValue;
+    }
+
+    /**
+     * @return the ViewCodeSequence_CodingSchemeDesignator
+     */
+    public String getViewCodeSequence_CodingSchemeDesignator() {
+        return ViewCodeSequence_CodingSchemeDesignator;
+    }
+
+    /**
+     * @param ViewCodeSequence_CodingSchemeDesignator the ViewCodeSequence_CodingSchemeDesignator to set
+     */
+    public void setViewCodeSequence_CodingSchemeDesignator(String ViewCodeSequence_CodingSchemeDesignator) {
+        this.ViewCodeSequence_CodingSchemeDesignator = ViewCodeSequence_CodingSchemeDesignator;
+    }
+
+    /**
+     * @return the ViewCodeSequence_CodingSchemeVersion
+     */
+    public String getViewCodeSequence_CodingSchemeVersion() {
+        return ViewCodeSequence_CodingSchemeVersion;
+    }
+
+    /**
+     * @param ViewCodeSequence_CodingSchemeVersion the ViewCodeSequence_CodingSchemeVersion to set
+     */
+    public void setViewCodeSequence_CodingSchemeVersion(String ViewCodeSequence_CodingSchemeVersion) {
+        this.ViewCodeSequence_CodingSchemeVersion = ViewCodeSequence_CodingSchemeVersion;
+    }
+
+    /**
+     * @return the ViewCodeSequence_CodeMeaning
+     */
+    public String getViewCodeSequence_CodeMeaning() {
+        return ViewCodeSequence_CodeMeaning;
+    }
+
+    /**
+     * @param ViewCodeSequence_CodeMeaning the ViewCodeSequence_CodeMeaning to set
+     */
+    public void setViewCodeSequence_CodeMeaning(String ViewCodeSequence_CodeMeaning) {
+        this.ViewCodeSequence_CodeMeaning = ViewCodeSequence_CodeMeaning;
+    }
+
+    /**
+     * @return the ViewPosition
+     */
+    public String getViewPosition() {
+        return ViewPosition;
+    }
+
+    /**
+     * @param ViewPosition the ViewPosition to set
+     */
+    public void setViewPosition(String ViewPosition) {
+        this.ViewPosition = ViewPosition;
+    }
+
+    /**
+     * @return the ImageLaterality
+     */
+    public String getImageLaterality() {
+        return ImageLaterality;
+    }
+
+    /**
+     * @param ImageLaterality the ImageLaterality to set
+     */
+    public void setImageLaterality(String ImageLaterality) {
+        this.ImageLaterality = ImageLaterality;
+    }
+
+    /**
+     * @return the AcquisitionDeviceProcessingDescription
+     */
+    public String getAcquisitionDeviceProcessingDescription() {
+        return AcquisitionDeviceProcessingDescription;
+    }
+
+    /**
+     * @param AcquisitionDeviceProcessingDescription the AcquisitionDeviceProcessingDescription to set
+     */
+    public void setAcquisitionDeviceProcessingDescription(String AcquisitionDeviceProcessingDescription) {
+        this.AcquisitionDeviceProcessingDescription = AcquisitionDeviceProcessingDescription;
+    }
+    
+    public String toString()
+    {
+    
+        
+        String result = "";
+        result += "SeriesInstanceUID:" + SerieInstanceUID + "\n";
+        result += "SeriesDescription:" + SeriesDescription + "\n";
+        result += "SerieNumber:" + SerieNumber + "\n";
+        result += "Modality:" + Modality + "\n";
+        return result;
+        
+    }
+    
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Study.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Study.java
new file mode 100755
index 0000000..dab75cd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/dim/Study.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.dim;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class Study {
+
+    private Patient parent;
+    private String StudyInstanceUID ;
+    private String StudyID;
+    private String StudyData ;
+    private String StudyTime ;
+    private String AccessionNumber;
+    private String StudyDescription;
+    private String InstitutuionName;
+
+    private String operatorsName;
+    private String RequestingPhysician;
+
+    // Look in the cases where there same patient identifier with different
+    // patient names
+    private String patientName;
+
+
+    private ArrayList<Serie> series = new ArrayList<Serie>() ;
+    private Hashtable<String, Serie> seriesHash = new Hashtable<String, Serie>();
+
+    public Study(Patient patient, String StudyInstanceUID, String StudyDate)
+    {
+        this.parent = patient;
+        this.StudyInstanceUID = StudyInstanceUID ;
+        this.StudyData = StudyDate ;
+
+    }
+
+
+    public String getPatientName() {
+        return patientName;
+    }
+
+    public void setPatientName(String patientName) {
+        this.patientName = patientName;
+    }
+
+
+    /**
+     * @return the StudyInstanceUID
+     */
+    public String getStudyInstanceUID() {
+        return StudyInstanceUID;
+    }
+
+    /**
+     * @param StudyInstanceUID the StudyInstanceUID to set
+     */
+    public void setStudyInstanceUID(String StudyInstanceUID) {
+        this.StudyInstanceUID = StudyInstanceUID;
+    }
+
+    /**
+     * @return the StudyData
+     */
+    public String getStudyData() {
+        return StudyData;
+    }
+
+    /**
+     * @param StudyData the StudyData to set
+     */
+    public void setStudyData(String StudyData) {
+        this.StudyData = StudyData;
+    }
+
+
+
+    public void addSerie(Serie s){
+        if (this.seriesHash.containsKey(s.getSerieInstanceUID())){
+
+            Serie existSerie = this.seriesHash.get(s.getSerieInstanceUID());
+            ArrayList<URI> img = s.getImageList();
+            ArrayList<String> uid = s.getSOPInstanceUIDList();
+
+            int size = img.size();
+            for (int i=0;i<size;i++){
+                existSerie.addImage(img.get(i),uid.get(i));
+            }
+        }
+        else
+        {
+            this.series.add(s);
+            this.seriesHash.put(s.getSerieInstanceUID(), s) ;
+        }
+
+    }
+
+    /**
+     * @return the series
+     */
+    public ArrayList<Serie> getSeries() {
+        return series;
+    }
+
+    public Serie getSeries(String seriesInstanceUID) {
+        return this.seriesHash.get(seriesInstanceUID);
+    }
+
+    /**
+     * @param series the series to set
+     */
+    public void setSeries(ArrayList<Serie> series) {
+        this.series = series;
+    }
+
+    /**
+     * @return the parent
+     */
+    public Patient getParent() {
+        return parent;
+    }
+
+    /**
+     * @return the StudyTime
+     */
+    public String getStudyTime() {
+        return StudyTime;
+    }
+
+    /**
+     * @param StudyTime the StudyTime to set
+     */
+    public void setStudyTime(String StudyTime) {
+        this.StudyTime = StudyTime;
+    }
+
+    /**
+     * @return the AccessionNumber
+     */
+    public String getAccessionNumber() {
+        return AccessionNumber;
+    }
+
+    /**
+     * @param AccessionNumber the AccessionNumber to set
+     */
+    public void setAccessionNumber(String AccessionNumber) {
+        this.AccessionNumber = AccessionNumber;
+    }
+
+    /**
+     * @return the StudyDescription
+     */
+    public String getStudyDescription() {
+        return StudyDescription;
+    }
+
+    /**
+     * @param StudyDescription the StudyDescription to set
+     */
+    public void setStudyDescription(String StudyDescription) {
+        this.StudyDescription = StudyDescription;
+    }
+
+    /**
+     * @return the StudyID
+     */
+    public String getStudyID() {
+        return StudyID;
+    }
+
+    /**
+     * @param StudyID the StudyID to set
+     */
+    public void setStudyID(String StudyID) {
+        this.StudyID = StudyID;
+    }
+
+    /**
+     * @return the InstitutuionName
+     */
+    public String getInstitutuionName() {
+        return InstitutuionName;
+    }
+
+    /**
+     * @param InstitutuionName the InstitutuionName to set
+     */
+    public void setInstitutuionName(String InstitutuionName) {
+        this.InstitutuionName = InstitutuionName;
+    }
+
+
+    /**
+     * @return the operatorsName
+     */
+    public String getOperatorsName() {
+        return operatorsName;
+    }
+
+    /**
+     * @param operatorsName the operatorsName to set
+     */
+    public void setOperatorsName(String operatorsName) {
+        this.operatorsName = operatorsName;
+    }
+
+    /**
+     * @return the RequestingPhysician
+     */
+    public String getRequestingPhysician() {
+        return RequestingPhysician;
+    }
+
+    /**
+     * @param RequestingPhysician the RequestingPhysician to set
+     */
+    public void setRequestingPhysician(String RequestingPhysician) {
+        this.RequestingPhysician = RequestingPhysician;
+    }
+
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/exceptions/CFindNotSupportedException.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/exceptions/CFindNotSupportedException.java
new file mode 100755
index 0000000..5186704
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/exceptions/CFindNotSupportedException.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.exceptions;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CFindNotSupportedException extends Exception
+{
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/core/query/ExportToCSVQueryTask.java b/dicoogle/src/main/java/pt/ua/dicoogle/core/query/ExportToCSVQueryTask.java
new file mode 100644
index 0000000..61e8d9c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/core/query/ExportToCSVQueryTask.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.query;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+public class ExportToCSVQueryTask extends JointQueryTask {
+
+	private static final Logger log = LoggerFactory.getLogger(ExportToCSVQueryTask.class);
+	
+	private static String[] searchChars = new String[]{"\n", ";"};
+	private static String[] replaceChars = new String[]{"", ","};
+	
+	private List<String> tagsOrder;
+	// private OutputStream outputStream;
+	private PrintWriter writter;
+	private CountDownLatch latch;
+	
+	private int nLines = 0;
+
+	public ExportToCSVQueryTask(List<String> tagsOrder, OutputStream outputStream) {
+		super();
+		this.tagsOrder = tagsOrder;
+		this.latch = new CountDownLatch(1);
+		writter = new PrintWriter(outputStream);
+
+		printFirstLine();
+	}
+
+	@Override
+	public void onCompletion() {
+		log.debug("ExportToCSV task: completed");
+		writter.flush();
+		writter.close();
+		latch.countDown();
+		
+		log.info("Exported CSV Table: ", tagsOrder.toString(), nLines);
+	}
+
+	@Override
+	public void onReceive(Task<Iterable<SearchResult>> e) {
+		log.debug("ExportToCSV task: Received results");
+		try {
+			Iterable<SearchResult> it = e.get();
+			for (SearchResult result : it) {
+				printLine(result);
+			}
+		} catch (InterruptedException | ExecutionException e1) {
+			e1.printStackTrace();
+		}
+
+	}
+
+	/**
+	 * Print the first line of the .csv file
+	 * 
+	 */
+	private void printFirstLine() {
+		StringBuilder builder = new StringBuilder();
+		
+		log.debug("Started, Printing first line: ", tagsOrder);
+		
+		for (String tag : tagsOrder) {
+			builder.append("\"").append(tag).append("\";");
+		}
+
+		this.writter.println(builder.toString());
+	}
+
+	private void printLine(SearchResult result){
+		StringBuilder builder = new StringBuilder();
+		
+		HashMap<String, Object> extraFields = result.getExtraData();
+		
+		for (String tag : tagsOrder) {
+			Object temp1 = extraFields.get(tag);
+
+			final String s = (temp1 != null) ?
+				temp1.toString().trim() : "";
+
+			if (s.length() > 0) {
+				String temp = StringUtils.replaceEach(s, searchChars, replaceChars);
+				builder.append('\"').append(temp).append("\";");
+			} else {
+				builder.append(";");
+			}
+		}
+		
+		log.trace("Printing Line: ", builder.toString());
+		nLines++;
+		this.writter.println(builder.toString());
+	}
+
+	public void await() {
+		try {
+			latch.await();
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
+	}
+	
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DefaultFileStoragePlugin.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DefaultFileStoragePlugin.java
new file mode 100644
index 0000000..5e32af8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DefaultFileStoragePlugin.java
@@ -0,0 +1,213 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import metal.utils.fileiterator.FileIterator;
+
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.io.DicomInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.PluginBase;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+
+public class DefaultFileStoragePlugin extends PluginBase implements StorageInterface{
+
+	private static final Logger logger = LoggerFactory.getLogger(DefaultFileStoragePlugin.class);
+	
+	private String defaultScheme = "file";
+	
+	public DefaultFileStoragePlugin() {
+		super();
+		super.storagePlugins.add(this);
+	}
+
+	@Override
+	public boolean enable() {
+		return true;
+	}
+
+	@Override
+	public boolean disable() {
+		return false;
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return true;
+	}
+
+	@Override
+	public String getScheme() {
+		return defaultScheme;
+	}
+
+	@Override
+	public boolean handles(URI location) {
+		if (location.getScheme() == null)
+			return true;
+		return location.getScheme().equals(defaultScheme);
+	}
+	
+	private Iterator<StorageInputStream> createIterator(URI location){
+		if(!handles(location)){
+			logger.error("Cannot Handle: "+location.toString());
+			return Collections.emptyIterator();
+		}
+
+		logger.debug("Stared creating Iterator in: "+location.getSchemeSpecificPart()); 
+		File parent = new File(location.getSchemeSpecificPart());
+		Iterator<File> fileIt;
+		
+		if (parent.isDirectory()) {
+			logger.debug("Location is a directory: "+location.getSchemeSpecificPart());
+			fileIt = new FileIterator(parent);
+		} else {
+			List<File> files = new ArrayList<>(1);
+			files.add(parent);
+			fileIt = files.iterator();
+		}
+
+		logger.debug("Finished assembling Iterator: "+ location.getSchemeSpecificPart());
+		return new MyIterator(fileIt);
+	}
+
+	@Override
+	public Iterable<StorageInputStream> at(URI location, Object ... args) {
+		return new MyIterable(location);		
+	}
+
+	@Override
+	public URI store(DicomObject dicomObject, Object ... args) {
+		return null;
+	}
+
+	@Override
+	public URI store(DicomInputStream inputStream, Object ... args) throws IOException {
+		return null;
+	}
+
+	@Override
+	public void remove(URI location) {
+		if (!location.getScheme().equals(defaultScheme)) {
+			return;
+		}
+
+		String path = location.getSchemeSpecificPart();
+		File f = new File(path);
+		if (f.exists()) {
+			f.delete();
+		}		
+	}
+
+	@Override
+	public String getName() {
+		return "default-filesystem-plugin";
+	}
+
+	private class MyIterable implements Iterable<StorageInputStream>{
+
+		private URI baseLocation;
+
+		public MyIterable(URI baseLocation) {
+			super();
+			this.baseLocation = baseLocation;
+		}
+
+		@Override
+		public Iterator<StorageInputStream> iterator() {
+			// TODO Auto-generated method stub
+			return createIterator(baseLocation);
+		}
+		
+	}
+	
+	private static class MyIterator implements Iterator<StorageInputStream>{
+	
+		private Iterator<File> it;
+		
+		public MyIterator(Iterator<File> it) {
+			super();
+			this.it = it;
+		}
+
+		@Override
+		public boolean hasNext() {
+			return it.hasNext();
+		}
+
+		@Override
+		public StorageInputStream next() {
+			if(!it.hasNext())
+				return null;
+			File f = it.next();
+			logger.debug("Added File: "+f.toURI());
+			MyDICOMInputString stream = new MyDICOMInputString(f);			
+			return stream;
+		}
+
+		@Override
+		public void remove() {
+			// TODO Auto-generated method stub
+			
+		}
+	}
+	
+	private static class MyDICOMInputString implements StorageInputStream{
+		
+		private File file;
+
+		public MyDICOMInputString(File file) {
+			super();
+			this.file = file;
+		}
+
+		@Override
+		public URI getURI() {
+			return file.toURI();
+		}
+
+		@Override
+		public InputStream getInputStream() throws IOException {
+			// TODO Auto-generated method stub
+			return new BufferedInputStream(new FileInputStream(file));
+		}
+
+		@Override
+		public long getSize() throws IOException {
+			// TODO Auto-generated method stub
+			return file.length();
+		}
+		
+	}
+		
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DicooglePlatformProxy.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DicooglePlatformProxy.java
new file mode 100644
index 0000000..fb2197c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/DicooglePlatformProxy.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import pt.ua.dicoogle.core.ServerSettings;
+
+import pt.ua.dicoogle.sdk.IndexerInterface;
+import pt.ua.dicoogle.sdk.QueryInterface;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface;
+import pt.ua.dicoogle.sdk.core.ServerSettingsReader;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * A proxy to the implementations of Plugin Controller.
+ * 
+ * @author psytek
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class DicooglePlatformProxy implements DicooglePlatformInterface {
+
+    private final PluginController pluginController;
+    
+    public DicooglePlatformProxy(PluginController pluginController){
+        this.pluginController = pluginController;
+    }
+    
+    @Override
+    public IndexerInterface requestIndexPlugin(String name) {
+        Collection<IndexerInterface> indexers = pluginController.getIndexingPlugins(true);
+        for(IndexerInterface index : indexers){
+            if(index.getName().equals(name)) return index;
+        }
+        return null;
+    }
+
+    @Override
+    public QueryInterface requestQueryPlugin(String name) {
+        Collection<QueryInterface> queriers = pluginController.getQueryPlugins(true);
+        for(QueryInterface querier : queriers){
+            if(querier.getName().equals(name)) return querier;
+        }
+        
+        return null;
+    }
+
+    @Override
+    public Collection<IndexerInterface> getAllIndexPlugins() {
+        return pluginController.getIndexingPlugins(false);
+    }
+
+    @Override
+    public Collection<QueryInterface> getAllQueryPlugins() {
+        return pluginController.getQueryPlugins(false);
+    }
+
+    @Override
+    public StorageInterface getStoragePluginForSchema(String storage) {
+        return pluginController.getStorageForSchema(storage);
+    }
+
+    @Override
+    public StorageInterface getStorageForSchema(URI location) {
+        return pluginController.getStorageForSchema(location);
+    }
+
+    @Override
+    public Iterable<StorageInputStream> resolveURI(URI location, Object ...args) {
+        return pluginController.resolveURI(location, args);
+    }
+
+    @Override
+	public Collection<StorageInterface> getStoragePlugins(boolean onlyEnabled) {
+		return pluginController.getStoragePlugins(onlyEnabled);
+	}
+
+    @Override
+	public StorageInterface getStorageForSchema(String schema) {
+		return pluginController.getStorageForSchema(schema);
+	}
+
+    @Override
+	public Collection<QueryInterface> getQueryPlugins(boolean onlyEnabled) {
+		return pluginController.getQueryPlugins(onlyEnabled);
+	}
+
+    @Override
+	public List<String> getQueryProvidersName(boolean enabled) {
+		return pluginController.getQueryProvidersName(enabled);
+	}
+
+    @Override
+	public QueryInterface getQueryProviderByName(String name,
+			boolean onlyEnabled) {
+		return pluginController.getQueryProviderByName(name, onlyEnabled);
+	}
+
+    @Override
+	public JointQueryTask queryAll(JointQueryTask holder, String query,
+			Object... parameters) {
+		return pluginController.queryAll(holder, query, parameters);
+	}
+
+    @Override
+	public Task<Iterable<SearchResult>> query(String querySource, String query,
+			Object... parameters) {
+		return pluginController.query(querySource, query, parameters);
+	}
+
+    @Override
+	public JointQueryTask query(JointQueryTask holder,
+			List<String> querySources, String query, Object... parameters) {
+		return pluginController.query(holder, querySources, query, parameters);
+	}
+
+    @Override
+	public List<Task<Report>> index(URI path) {
+		return pluginController.index(path);
+	}
+
+    @Override
+	public List<Report> indexBlocking(URI path) {
+		return pluginController.indexBlocking(path);
+	}
+
+    @Override
+    public ServerSettingsReader getSettings() {
+        return ServerSettings.getInstance();
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/NetworkMember.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/NetworkMember.java
new file mode 100755
index 0000000..4551ec4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/NetworkMember.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins;
+
+import java.io.Serializable;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class NetworkMember implements Serializable
+{
+    private String peerName;
+    private String pluginName;
+
+    public NetworkMember(String peerName, String pluginName)
+    {
+        this.peerName = peerName;
+        this.pluginName = pluginName;
+    }
+
+    public String getPeerName()
+    {
+        return peerName;
+    }
+
+    public String getPluginName()
+    {
+        return pluginName;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginController.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginController.java
new file mode 100755
index 0000000..2b3e59a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginController.java
@@ -0,0 +1,829 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.io.FileUtils;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.webui.WebUIPlugin;
+import pt.ua.dicoogle.plugins.webui.WebUIPluginManager;
+import pt.ua.dicoogle.sdk.*;
+import pt.ua.dicoogle.sdk.Utils.TaskQueue;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.settings.ConfigurationHolder;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.server.ControlServices;
+import pt.ua.dicoogle.server.PluginRestletApplication;
+import pt.ua.dicoogle.server.web.DicoogleWeb;
+import pt.ua.dicoogle.taskManager.RunningIndexTasks;
+import pt.ua.dicoogle.taskManager.TaskManager;
+
+import javax.swing.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.zip.ZipFile;
+
+/**
+ *
+ * PluginController is the core of the Plugins architecture.
+ *
+ * <p>
+ * It loads the plugins, takes care of the list of active plugins and control
+ * the tasks that are exchanged between plugins and core plugins
+ *
+ * @author Carlos Ferreira
+ * @author Frederico Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Tiago Marques Godinho
+ * @author Eduardo Pinho
+ */
+public class PluginController{
+
+    private static final Logger logger = LoggerFactory.getLogger(PluginController.class);
+    private static PluginController instance;
+
+    public synchronized static PluginController getInstance() {
+        if (instance == null) {
+            instance = new PluginController(new File("Plugins"));
+        }
+        return instance;
+    }
+    private final Collection<PluginSet> pluginSets;
+    private File pluginFolder;
+    private TaskQueue tasks = null;
+
+	private PluginSet remoteQueryPlugins = null;
+    private final WebUIPluginManager webUI;
+    private final DicooglePlatformProxy proxy;
+    private TaskManager taskManager = new TaskManager(Integer.parseInt(System.getProperty("dicoogle.taskManager.nThreads", "4")));
+    
+    public PluginController(File pathToPluginDirectory) {
+    	logger.info("Creating PluginController Instance");
+        pluginFolder = pathToPluginDirectory;
+
+        tasks = new TaskQueue();
+
+        //the plugin directory does not exist. lets create it
+        if (!pathToPluginDirectory.exists()) {
+        	logger.info("Creating new Plugin Folder");
+            pathToPluginDirectory.mkdirs();
+        }
+
+        //loads the plugins
+        pluginSets = PluginFactory.getPlugins(pathToPluginDirectory);
+        //load web UI plugins (they are not Java, so the process is delegated to another entity)
+        this.webUI = new WebUIPluginManager();
+        // loadByPluginName all at "WebPlugins"
+        this.webUI.loadAll(new File("WebPlugins"));
+        
+        // go through each jar'd plugin and fetch their WebPlugins
+        for (File j : FileUtils.listFiles(pluginFolder, new String[]{"jar", "zip"}, false)) {
+            try {
+                this.webUI.loadAllFromZip(new ZipFile(j));
+            } catch (IOException ex) {
+                // ignore
+                logger.warn("Failed to load web UI plugins from {}: {}", j.getName(), ex.getMessage());
+            }
+        }
+        
+        logger.info("Loaded Local Plugins");
+
+        //loads plugins' settings and passes them to the plugin
+        File settingsFolder = new File(pluginFolder.getPath() + "/settings/");
+        if (!settingsFolder.exists()) {
+        	logger.info("Creating Local Settings Folder");
+            settingsFolder.mkdir();
+        }
+
+        for (Iterator<PluginSet> it = pluginSets.iterator(); it.hasNext();) {
+            PluginSet plugin = it.next();
+            logger.info("Loading plugin: " + plugin.getName());
+            File pluginSettingsFile = new File(settingsFolder + "/" + plugin.getName().replace('/', '-') + ".xml");
+            try {
+                ConfigurationHolder holder = new ConfigurationHolder(pluginSettingsFile);
+                if(plugin.getName().equals("RemotePluginSet")) {
+                	this.remoteQueryPlugins = plugin;
+                	holder.getConfiguration().setProperty("NodeName", ServerSettings.getInstance().getNodeName());
+    	        	holder.getConfiguration().setProperty("TemporaryPath", ServerSettings.getInstance().getPath());
+                	
+                	logger.info("Started Remote Communications Manager");
+                }
+                applySettings(plugin, holder);
+            }
+            catch (ConfigurationException e){
+                logger.error("Failed to create configuration holder", e);
+			}
+            catch (RuntimeException e) {
+                logger.error("Unexpected error while loading plugin set {}. Plugin disabled.", plugin.getName(), e);
+                it.remove();
+            }
+        }
+        logger.info("Settings pushed to plugins");
+        webUI.loadSettings(settingsFolder);
+        logger.info("Settings pushed to web UI plugins");
+        
+        pluginSets.add(new DefaultFileStoragePlugin());
+        logger.info("Added default storage plugin");
+        
+        this.proxy = new DicooglePlatformProxy(this);
+        
+        initializePlugins(pluginSets);
+        initRestInterface(pluginSets);
+        initJettyInterface(pluginSets);
+        logger.info("Initialized plugins");
+    }
+    
+    private void initializePlugins(Collection<PluginSet> plugins) {
+        for (PluginSet set : plugins) {
+            logger.debug("SetPlugins: {}", set);
+            
+            // provide platform to each plugin interface
+            final Collection<Collection<?>> all = Arrays.asList(
+                    set.getStoragePlugins(),
+                    set.getIndexPlugins(),
+                    set.getQueryPlugins(),
+                    set.getJettyPlugins(),
+                    set.getRestPlugins()
+            );
+            for (Collection interfaces : all) {
+                if (interfaces == null) {
+                    logger.debug("Plugin set {} provided a null collection!");
+                    continue;
+                }
+                for (Object o : interfaces) {
+                    if (o instanceof PlatformCommunicatorInterface) {
+                        ((PlatformCommunicatorInterface)o).setPlatformProxy(proxy);
+                    }
+                }
+            }
+
+            // and to the set itself
+            if (set instanceof PlatformCommunicatorInterface) {
+                ((PlatformCommunicatorInterface) set).setPlatformProxy(proxy);
+            }
+        }
+    }
+    
+    private void applySettings(PluginSet set, ConfigurationHolder holder) {
+        // provide platform to each plugin interface
+        final Collection<Collection<? extends DicooglePlugin>> all = Arrays.asList(
+                set.getStoragePlugins(),
+                set.getIndexPlugins(),
+                set.getQueryPlugins(),
+                set.getJettyPlugins()
+        );
+        for (Collection<? extends DicooglePlugin> interfaces : all) {
+            if (interfaces == null) continue;
+            for (DicooglePlugin p : interfaces) {
+                p.setSettings(holder);
+            }
+        }
+        set.setSettings(holder);
+
+    }
+    
+    /**
+     * Each pluginSet provides a collection of barebone rest interfaces Here we
+     * check which interfaces are present and create a restlet component to
+     * handle them. also we export them using common settings and security
+     * profiles
+     */
+    private void initRestInterface(Collection<PluginSet> plugins) {
+        logger.info("Initializing plugin rest interfaces");
+
+        ArrayList<ServerResource> restInterfaces = new ArrayList<>();
+        for (PluginSet set : plugins) {
+            Collection<ServerResource> restInterface = set.getRestPlugins();
+            if (restInterface == null) {
+                continue;
+            }
+            restInterfaces.addAll(restInterface);
+        }
+
+        for (ServerResource resource : restInterfaces) {
+            PluginRestletApplication.attachRestPlugin(resource);
+        }
+        logger.info("Finished initializing rest interfaces");
+    }
+
+    private void initJettyInterface(Collection<PluginSet> plugins) {
+        logger.info("Initializing jetty interface");
+                
+         ArrayList<JettyPluginInterface> jettyInterfaces = new ArrayList<>();
+         for(PluginSet set : plugins){
+        	 Collection<JettyPluginInterface> jettyInterface = set.getJettyPlugins();
+        	 if(jettyInterface == null) continue;
+        	 jettyInterfaces.addAll(jettyInterface);
+         }
+         
+         DicoogleWeb jettyServer = ControlServices.getInstance().getWebServicePlatform();
+         for(JettyPluginInterface resource : jettyInterfaces){
+        	 jettyServer.addContextHandlers( resource.getJettyHandlers() );
+         }
+    }
+
+    /**
+     * Stops the plugins and saves the settings
+     */
+    public void shutdown() throws IOException {
+        for (PluginSet plugin : pluginSets) {
+            //TODO: I Think it is better to enable auto-save settings
+            /*Settings settings = plugin.getSettings();
+            if (settings != null) {
+                settings.save();
+            }
+	*/
+            //lets the plugin know we are shutting down
+            plugin.shutdown();
+        }
+    }
+
+    /**
+     * stops a pluginset. this could be more efficient, however this is hardly a
+     * bottleneck TODO: needs more granularity, we should be able to stop only
+     * the indexers or the queryers
+     *
+     * @param pluginName
+     */
+    public void stopPlugin(String pluginName) {
+        for (PluginSet pluginSet : pluginSets) {
+            if (pluginSet.getName().compareTo(pluginName) == 0) {
+                //pluginSet.stop();
+                return;
+            }
+        }
+    }
+
+    public void startPlugin(String pluginName) {
+        for (PluginSet pluginSet : pluginSets) {
+            if (pluginSet.getName().compareTo(pluginName) == 0) {
+                //pluginSet.stop();
+                return;
+            }
+        }
+    }
+
+    public Collection<IndexerInterface> getIndexingPlugins(boolean onlyEnabled) {
+        ArrayList<IndexerInterface> indexers = new ArrayList<>();
+        for (PluginSet pSet : pluginSets) {
+            for (IndexerInterface index : pSet.getIndexPlugins()) {
+                if (!index.isEnabled() && onlyEnabled) {
+                    continue;
+                }
+                indexers.add(index);
+            }
+        }
+        return indexers;
+    }
+
+    public Collection<StorageInterface> getStoragePlugins(boolean onlyEnabled) {
+        ArrayList<StorageInterface> storagePlugins = new ArrayList<>();
+        for (PluginSet pSet : pluginSets) {
+            for (StorageInterface store : pSet.getStoragePlugins()) {
+                if (!store.isEnabled() && onlyEnabled) {
+                    continue;
+                }
+                storagePlugins.add(store);
+            }
+        }
+        return storagePlugins;
+    }
+
+    /**
+     * Resolve a URI to a DicomInputStream
+     * @param location
+     * @param args
+     * @return 
+     */
+    public Iterable<StorageInputStream> resolveURI(URI location, Object ...args)
+    {
+        Collection<StorageInterface> storages = getStoragePlugins(true);
+        
+        for (StorageInterface store : storages) {
+            if (store.handles(location)) 
+            {
+            	logger.debug("Resolving URI: {} Storage: {}", location, store.getName());
+                return store.at(location, args);
+            }
+        }
+
+    	logger.error("Could not resolve uri: {}", location);
+        return Collections.emptyList();    
+    }
+    
+    /** Retrieve a storage interface capable of handling files on a given location.
+     * 
+     * TODO: this can be heavily improved if we keep a map of scheme->indexer
+     * However we are not supposed to call this every other cycle.
+     *
+     * TODO: we should return a proxy storage that always returns error
+     * 
+     * @todo "schema" is a typo, should read "scheme"
+     * 
+     * @param location a URI of the location, only the scheme matters
+     * @return a storage interface capable of handling the location, null if no suitable plugin is found
+     */
+    public StorageInterface getStorageForSchema(URI location) {
+    	if(location == null){
+            logger.warn("URI for retrieving storage interface is null, ignoring");
+            return null;
+    	}
+        Collection<StorageInterface> storages = getStoragePlugins(false);
+        
+        for (StorageInterface store : storages) {
+            try {
+                if (store.handles(location)) {
+                    logger.debug("Retrieved storage for scheme: {}", location);
+                    return store;
+                }
+            } catch (RuntimeException ex) {
+                logger.warn("Storage plugin {} failed unexpectedly", store.getName(), ex);
+            }
+        }
+        logger.warn("Could not get storage for scheme: {}", location);
+        return null;
+    }
+    
+    /** Retrieve a storage interface capable of handling files with the given scheme.
+     * 
+     * TODO: this can be heavily improved if we keep a map of scheme->indexer
+     * However we are not supposed to call this every other cycle.
+     *
+     * TODO: we should return a proxy storage that always returns error
+     * 
+     * @param scheme a URI of the location, only the scheme matters
+     * @return a storage interface capable of handling the location, null if no suitable plugin is found
+     */
+    public StorageInterface getStorageForSchema(String scheme) {
+        URI uri = URI.create(scheme + ":/");
+        return getStorageForSchema(uri);
+    }
+
+    public Collection<QueryInterface> getQueryPlugins(boolean onlyEnabled) {
+        ArrayList<QueryInterface> queriers = new ArrayList<>();
+        for (PluginSet pSet : pluginSets) {
+            for (QueryInterface querier : pSet.getQueryPlugins()) {
+                if (!querier.isEnabled() && onlyEnabled) {
+                    continue;
+                }
+                queriers.add(querier);
+            }
+        }
+        return queriers;
+    }
+
+    public void addTask(TaskRequest task) {
+        this.tasks.addTask(task);
+    }
+   
+
+    
+    public List<String> getQueryProvidersName(boolean enabled){
+    	Collection<QueryInterface> plugins = getQueryPlugins(enabled);
+    	List<String> names = new ArrayList<>(plugins.size());
+    	for(QueryInterface p : plugins){
+    		names.add(p.getName());
+    	}
+    	//logger.info("Query Providers: "+Arrays.toString(names.toArray()) );
+    	return names;
+    }
+    
+    public QueryInterface getQueryProviderByName(String name, boolean onlyEnabled){
+    	Collection<QueryInterface> plugins = getQueryPlugins(onlyEnabled);
+    	for(QueryInterface p : plugins){
+    		if(p.getName().equalsIgnoreCase(name)){
+    			//logger.info("Retrived Query Provider: "+name);
+    			return p;
+    		}
+    	}
+    	logger.error("Could not retrieve query provider {} for onlyEnabled = {}", name, onlyEnabled);
+    	return null;
+    }
+    
+    //TODO: CONVENIENCE METHOD
+    public IndexerInterface getIndexerByName(String name, boolean onlyEnabled){
+    	Collection<IndexerInterface> plugins = getIndexingPlugins(onlyEnabled);
+    	for(IndexerInterface p : plugins){
+    		if(p.getName().equalsIgnoreCase(name)){
+    			//logger.info("Retrived Query Provider: "+name);
+    			return p;
+    		}
+    	}
+    	logger.error("No indexer matching name {} for onlyEnabled = {}", name, onlyEnabled);
+    	return null;
+    }
+    
+    public JointQueryTask queryAll(JointQueryTask holder, final String query, final Object ... parameters)
+    {
+    	//logger.info("Querying all providers");
+    	List<String> providers = this.getQueryProvidersName(true);
+    	
+    	return query(holder, providers, query, parameters);        
+    }
+    
+    public Task<Iterable<SearchResult>> query(String querySource, final String query, final Object ... parameters){
+        Task<Iterable<SearchResult>> t = getTaskForQuery(querySource, query, parameters);       
+        taskManager.dispatch(t);
+        //logger.info("Fired Query Task: "+querySource +" QueryString:"+query);
+        
+        return t;//returns the handler to obtain the computation results
+    }
+    
+    public JointQueryTask query(JointQueryTask holder, List<String> querySources, final String query, final Object ... parameters){
+        if(holder == null)
+        	return null;
+    	
+    	List<Task<Iterable<SearchResult>>> tasks = new ArrayList<>();
+        for(String p : querySources){
+        	Task<Iterable<SearchResult>> task = getTaskForQuery(p, query, parameters);
+        	tasks.add(task);
+        	holder.addTask(task);
+        }
+
+        //and executes said task asynchronously
+        for(Task<?> t : tasks)
+        	taskManager.dispatch(t);
+
+        //logger.info("Fired Query Tasks: "+Arrays.toString(querySources.toArray()) +" QueryString:"+query);
+        return holder;//returns the handler to obtain the computation results
+    }
+    
+    private Task<Iterable<SearchResult>> getTaskForQuery(final String querySource, final String query, final Object ... parameters){
+    	final QueryInterface queryEngine = getQueryProviderByName(querySource, true);
+    	//returns a tasks that runs the query from the selected query engine
+        Task<Iterable<SearchResult>> queryTask = new Task<>(querySource,
+            new Callable<Iterable<SearchResult>>(){
+            @Override public Iterable<SearchResult> call() throws Exception {
+                if(queryEngine == null) return Collections.emptyList();
+                try {
+                    return queryEngine.query(query, parameters);
+                } catch (RuntimeException ex) {
+                    logger.warn("Query plugin {} failed unexpectedly", querySource, ex);
+                    return Collections.EMPTY_LIST;
+                }
+            }
+        });
+        //logger.info("Prepared Query Task: QueryString");
+        return queryTask;
+    }        
+ 
+    /*
+     * Given an URI (which may be a path to a dir or file, a web resource or whatever)
+     * this method creates a task that
+     * calls the appropriate indexers and instructs them to index the data pointed to by the URI
+     * it is up to the caller to run the task asynchronously by feeding it to an executor
+     * or in a blocking way by calling the get() method of the task
+     */
+    public List<Task<Report>> index(URI path) {
+    	logger.info("Starting Indexing procedure for {}", path.toString());
+        StorageInterface store = getStorageForSchema(path);
+
+        if(store==null){ 
+            logger.error("No storage plugin detected, ignoring index request");
+            return Collections.emptyList(); 
+        }
+        
+        Collection<IndexerInterface> indexers= getIndexingPlugins(true);
+        //Collection<IndexerInterface> indexers = getIndexingPluginsByMimeType(path);
+        ArrayList<Task<Report>> rettasks = new ArrayList<>();
+        final  String pathF = path.toString();
+        for(IndexerInterface indexer : indexers){
+            try {
+                Task<Report> task = indexer.index(store.at(path));
+                if(task == null) continue;
+                final String taskUniqueID = UUID.randomUUID().toString();
+                task.setName(String.format("[%s]index %s", indexer.getName(), path));
+                task.onCompletion(new Runnable() {
+                    @Override
+                    public void run() {
+                        logger.info("Task [{}] complete: {} is indexed", taskUniqueID, pathF);
+                    }
+                });
+
+                taskManager.dispatch(task);
+                rettasks.add(task);
+                RunningIndexTasks.getInstance().addTask(taskUniqueID, task);
+            } catch (RuntimeException ex) {
+                logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex);
+            }
+        }
+        logger.info("Finished firing all indexing plugins for {}", path);
+        
+        return rettasks;    	
+    }
+    
+    //
+    public List<Task<Report>> index(String pluginName, URI path) {
+    	logger.info("Starting Indexing procedure for {}", path);
+        StorageInterface store = getStorageForSchema(path);
+
+        if(store==null){ 
+        	logger.error("No storage plugin detected, ignoring index request");
+            return Collections.emptyList(); 
+        }
+        
+        final String taskUniqueID = UUID.randomUUID().toString();
+        
+        IndexerInterface indexer = getIndexerByName(pluginName, true);
+        ArrayList<Task<Report>> rettasks = new ArrayList<>();
+        final  String pathF = path.toString();
+        try {
+            Task<Report> task = indexer.index(store.at(path));
+            if (task != null) {
+                task.setName(String.format("[%s]index %s", pluginName, path));
+                task.onCompletion(new Runnable() {
+
+                    @Override
+                    public void run() {
+                        logger.info("Task [{}] complete: {} is indexed", taskUniqueID, pathF);
+
+                        //RunningIndexTasks.getInstance().removeTask(taskUniqueID);
+                    }
+                });
+
+                taskManager.dispatch(task);
+
+                rettasks.add(task);
+                logger.info("Fired indexer {} for URI {}", pluginName, path.toString());
+                RunningIndexTasks.getInstance().addTask(taskUniqueID, task);
+            }
+        } catch (RuntimeException ex) {
+            logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex);
+        }
+
+        return rettasks;    	
+    }
+
+    public void unindex(URI path) {
+    	logger.info("Starting unindexing procedure for {}", path.toString());
+        this.doUnindex(path, this.getIndexingPlugins(true));
+    }
+
+    /** Issue the removal of indexed entries in a path from the given indexers.
+     * 
+     * @param path the URI of the directory or file to unindex
+     * @param indexProviders a collection of providers
+     */
+    public void unindex(URI path, Collection<String> indexProviders) {
+    	logger.info("Starting unindexing procedure for {}", path);
+        
+        if (indexProviders != null) {
+            List<IndexerInterface> indexers = new ArrayList<>();
+            for (String provider : indexProviders) {
+                indexers.add(this.getIndexerByName(provider, true));
+            }
+            this.doUnindex(path, indexers);
+        } else {
+            this.doUnindex(path, this.getIndexingPlugins(true));
+        }
+    }
+    
+    /** Issue an unindexation procedure to the given indexers.
+     * 
+     * @param path the URI of the directory or file to unindex
+     * @param indexers a collection of providers
+     */
+    private void doUnindex(URI path, Collection<IndexerInterface> indexers) {
+        for (IndexerInterface indexer : indexers) {
+            try {
+                indexer.unindex(path);
+            } catch (RuntimeException ex) {
+                logger.warn("Indexer {} failed unexpectedly", indexer.getName(), ex);
+            }
+        }
+        logger.info("Finished unindexing {}", path);
+    }
+    
+    public void remove(URI uri){
+      StorageInterface si = getStorageForSchema(uri);
+      if(si != null)
+        doRemove(uri, si);
+      else
+        logger.error("Could not find storage plugin to handle URI: {}", uri);      
+    }
+    
+    public void doRemove(URI uri, StorageInterface si) {
+        try {
+            if (si.handles(uri)) {
+                si.remove(uri);
+            } else {
+                logger.warn("Storage Plugin does not handle URI: {},{}", uri, si);
+            }
+            logger.info("Finished removing {}", uri);
+        } catch (RuntimeException ex) {
+            logger.warn("Storage {} failed unexpectedly", si.getName(), ex);
+        }
+    }
+
+    /*
+     * Convenience method that calls index(URI) and runs the returned
+     * tasks on the executing thread 
+     */
+    public List<Report> indexBlocking(URI path) {
+    	logger.info("Starting indexing blocking procedure for {}", path);
+        List<Task<Report>> ret = index(path);
+        
+        ArrayList<Report> reports = new ArrayList<>(ret.size());
+        for(Task<Report> t : ret){
+        	try {
+				reports.add(t.get());
+			}
+            catch (InterruptedException | ExecutionException e) {
+                logger.error(e.getMessage(), e);
+			} catch (RuntimeException e) {
+                logger.warn("Indexer task failed unexpectedly", e);
+            }
+        }
+        logger.info("Finished indexing {}", path);
+        
+        return reports;
+    }
+
+    //METHODs FOR PluginController4Users
+    //TODO:this method is a workaround! we do get rightmenu items, but only for the search window
+    //which should be moved to plugins and hence we are assuming too much in here!
+ 
+    @Deprecated
+	public List<JMenuItem> getRightButtonItems() {
+        logger.info("getRightButtonItems()");
+        ArrayList<JMenuItem> rightMenuItems = new ArrayList<>();
+        
+        for (PluginSet set : pluginSets) {
+            logger.info("Set plugins: {}", set.getGraphicalPlugins());
+            Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins();
+            if (graphicalPlugins == null) {
+                continue;
+            }
+            logger.info("Looking for plugin");
+            for (GraphicalInterface gpi : graphicalPlugins) {
+                logger.info("GPI: {}", gpi);
+                ArrayList<JMenuItem> rbPanels = gpi.getRightButtonItems();
+                if (rbPanels == null) {
+                    continue;
+                }
+                rightMenuItems.addAll(rbPanels);
+            }
+        }
+        return rightMenuItems;
+    }
+
+    //returns a list of tabs from all plugins
+    @Deprecated
+    public List<JPanel> getTabItems() {
+        logger.info("getTabItems");
+        ArrayList<JPanel> panels = new ArrayList<>();
+
+        for (PluginSet set : pluginSets) {
+            Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins();
+            if (graphicalPlugins == null) {
+                continue;
+            }
+            for (GraphicalInterface gpi : graphicalPlugins) {
+                ArrayList<JPanel> tPanels = gpi.getTabPanels();
+                if (tPanels == null) {
+                    continue;
+                }
+                panels.addAll(tPanels);
+            }
+        }
+        return panels;
+    }
+
+    @Deprecated
+    public List<JMenuItem> getMenuItems() {
+        logger.info("getMenuItems");
+        ArrayList<JMenuItem> items = new ArrayList<>();
+
+        for (PluginSet set : pluginSets) {
+            Collection<GraphicalInterface> graphicalPlugins = set.getGraphicalPlugins();
+            if (graphicalPlugins == null) {
+                continue;
+            }
+
+            for (GraphicalInterface gpi : graphicalPlugins) {
+                Collection<JMenuItem> setItems = gpi.getMenuItems();
+                if (setItems == null) {
+                    continue;
+                }
+                items.addAll(setItems);
+            }
+        }
+        return items;
+    }
+    
+    // Methods for Web UI 
+
+    /** Retrieve all web UI plugin descriptors for the given slot id.
+     * 
+     * @param ids the slot id's for the plugin ("query", "result", "menu", ...), empty or null for any slot
+     * @return a collection of web UI plugins.
+     */
+    public Collection<WebUIPlugin> getWebUIPlugins(String... ids) {
+        logger.debug("getWebUIPlugins(slot ids: {})", ids != null ? Arrays.asList(ids) : "<any>");
+        List<WebUIPlugin> plugins = new ArrayList<>();
+        Set<String> idSet = Collections.EMPTY_SET;
+        if (ids != null) {
+            idSet = new HashSet<>(Arrays.asList(ids));
+        }
+        for (WebUIPlugin plugin : webUI.pluginSet()) {
+            if (!plugin.isEnabled()) {
+                continue;
+            }
+            if (idSet.isEmpty() || idSet.contains(plugin.getSlotId())) {
+                plugins.add(plugin);
+            }
+        }
+        return plugins;
+    }
+    
+    /** Retrieve the web UI plugin descriptor of the plugin with the given name.
+     * 
+     * @param name the unique name of the plugin
+     * @return a web UI plugin descriptor object, or null if no such plugin exists or is inactive
+     */
+    public WebUIPlugin getWebUIPlugin(String name) {
+        logger.debug("getWebUIPlugin(name: {})", name);
+        WebUIPlugin plugin = webUI.get(name);
+        return plugin == null ? null
+                : plugin.isEnabled() ? plugin : null;
+    }
+
+    /** Retrieve the web UI plugin descriptor package.json.
+     * 
+     * @param name the unique name of the plugin
+     * @return the full contents of the package.json, null if the plugin is not available
+     */
+    public String getWebUIPackageJSON(String name) {
+        logger.debug("getWebUIPackageJSON(name: {})", name);
+        try {
+            Object o = webUI.retrieveJSON(name);
+            return (o != null)
+                    ? o.toString()
+                    : null;
+        } catch (IOException ex) {
+            logger.error("Failed to retrieve package JSON", ex);
+            return null;
+        }
+    }
+
+    /** Retrieve the web UI plugin module code.
+     * 
+     * @param name the unique name of the plugin
+     * @return the full contents of the module file, null if the plugin is not available
+     */
+    public String getWebUIModuleJS(String name) {
+        logger.debug("getWebUIModuleJS(name: {})", name);
+        try {
+            return webUI.retrieveModuleJS(name);
+        } catch (IOException ex) {
+            logger.error("Failed to retrieve module", ex);
+            return null;
+        }
+    }
+
+    //METHODS FOR SERVICE:JAVA
+    /**
+     *
+     * TODO: REVIEW! BELOW
+     *
+     * Checks if the plugin exists and has advanced/internal settings.
+     *
+     * @param pluginName the name of the plugin.
+     * @return true if the plugin exists and has at least one advance/internal
+     * settings, false otherwise.
+     */
+    public boolean hasAdvancedSettings(String pluginName) {
+        return false;
+    }
+
+    public HashMap<String, String> getAdvancedSettingsHelp(String pluginName) {
+        return null;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginFactory.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginFactory.java
new file mode 100644
index 0000000..0ca1c11
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginFactory.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.plugins;
+
+import java.io.File;
+import java.util.Collection;
+
+import net.xeoh.plugins.base.PluginManager;
+import net.xeoh.plugins.base.impl.PluginManagerFactory;
+import net.xeoh.plugins.base.util.PluginManagerUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.PluginSet;
+
+/** A collection of factory methods for retrieving Dicoogle plugins from a directory.
+ * 
+ * @author psytek
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+
+public class PluginFactory {
+    private static final Logger logger = LoggerFactory.getLogger(PluginFactory.class);
+    
+    public static Collection<PluginSet> getPlugins(File pluginDirectory){
+        if (pluginDirectory == null) {
+            throw new NullPointerException("pluginDirectory");
+        }
+        if (!pluginDirectory.isDirectory()) {
+            throw new IllegalArgumentException("Plugin base must be a directory");
+        }
+        PluginManager pm = PluginManagerFactory.createPluginManager();
+        logger.debug("Plugin Directory: {}", pluginDirectory.getAbsolutePath());
+        pm.addPluginsFrom(pluginDirectory.toURI());
+        PluginManagerUtil pmu = new PluginManagerUtil(pm);
+        return pmu.getPlugins(PluginSet.class);
+    }
+    
+     public static Collection<PluginSet> getPlugins(){
+        return getPlugins(new File("Plugins"));
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginPanelLoader.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginPanelLoader.java
new file mode 100755
index 0000000..a7fd546
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/PluginPanelLoader.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins;
+
+/**
+ * Dummie Class Loader, only to get the Class Name in a simple way
+ * @author Carlos Ferreira
+ */
+public class PluginPanelLoader extends ClassLoader
+{
+
+    private static PluginPanelLoader instance = null;
+
+    private PluginPanelLoader(ClassLoader parent)
+    {
+        super(parent);
+    }
+
+    private PluginPanelLoader()
+    {
+        super(getSystemClassLoader());
+    }
+
+    private static synchronized PluginPanelLoader getInstance()
+    {
+        if (instance == null)
+        {
+            instance = new PluginPanelLoader();
+        }
+        return instance;
+    }
+
+    private static synchronized PluginPanelLoader getInstance(ClassLoader cl)
+    {
+        if (instance == null)
+        {
+            instance = new PluginPanelLoader(cl);
+        }
+        return instance;
+    }
+
+   /* @Override
+    public Class<?> loadClass(String name)
+    {
+        try
+        {
+            IPluginControllerAdmin plugins = AdminRefs.getInstance().getPluginController();
+            HashMap<String, byte[]> panelClasses = plugins.getPanelClasses();
+            Set<String> keys = panelClasses.keySet();
+            for (String key : keys)
+            {
+                byte[] pp = panelClasses.get(key);
+
+                ClassLoader cl = PluginPanel.class.getClassLoader();
+                Class c = defineClass(pp);
+
+                return c;
+            }
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(PluginPanelLoader.class).error(ex.getMessage(), ex);
+        }
+        return null;
+    }
+
+    @Override
+    public Class<?> loadClass(String name, boolean resolve)
+    {
+        try
+        {
+            IPluginControllerAdmin plugins = AdminRefs.getInstance().getPluginController();
+            HashMap<String, byte[]> panelClasses = plugins.getPanelClasses();
+            Set<String> keys = panelClasses.keySet();
+            for (String key : keys)
+            {
+                byte[] pp = panelClasses.get(key);
+
+                //ClassLoader cl = PluginPanel.class.getClassLoader();
+                Class c = defineClass(pp);
+
+                return c;
+            }
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(PluginPanelLoader.class).error(ex.getMessage(), ex);
+        }
+        return null;
+    }*/
+
+    public Class defineClass(byte[] b)
+    {
+        Class c = defineClass(null, b, 0, b.length);
+        //System.out.println(c.getName().substring(0, c.getName().lastIndexOf('.')));
+        //super.definePackage(c.getPackage().getName(), c.getPackage().getSpecificationTitle(), c.getPackage().getSpecificationVersion(), c.getPackage().getSpecificationVendor(),
+        //        c.getPackage().getImplementationTitle(), c.getPackage().getImplementationVersion(), c.getPackage().getImplementationVendor(), null);
+        super.resolveClass(c);
+        //System.out.println(c.getClassLoader().toString());
+        return c;
+        /*     try
+        {
+        this.loadClass(c.getName());
+        System.out.println(c.getName());
+        } catch (ClassNotFoundException ex)
+        {
+        LoggerFactory.getLogger(ServerOptions.class).error(ex.getMessage(), ex);
+        }*/
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/PluginFormatException.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/PluginFormatException.java
new file mode 100644
index 0000000..29499ce
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/PluginFormatException.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins.webui;
+
+/** An exception for describing an issue when reading a web UI plugin descriptor.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class PluginFormatException extends Exception {
+
+    public PluginFormatException() {
+    }
+
+    public PluginFormatException(String string) {
+        super(string);
+    }
+
+    public PluginFormatException(String string, Throwable thrwbl) {
+        super(string, thrwbl);
+    }
+
+    public PluginFormatException(Throwable thrwbl) {
+        super(thrwbl);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPlugin.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPlugin.java
new file mode 100644
index 0000000..d7b1726
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPlugin.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins.webui;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.server.users.Role;
+import pt.ua.dicoogle.server.users.RolesStruct;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** A POJO data type containing the full description of a Web UI plugin.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class WebUIPlugin implements Cloneable {
+    private String name;
+    private String caption;
+    private String description;
+    private String version;
+    private String slotId;
+    private String moduleFile;
+    private JSONObject settings;
+    private boolean enabled = true;
+    private Set<String> roles = new HashSet();
+
+    public WebUIPlugin() {}
+
+    @Override
+    protected WebUIPlugin clone() throws CloneNotSupportedException {
+        return (WebUIPlugin)super.clone();
+    }
+
+    /** Make a copy of the descriptor.
+     * @return a copy of this descriptor
+     * @todo The settings are shallowly copied at the moment. Hopefully this will not be a problem, but
+     * bear this in mind.
+     */
+    public WebUIPlugin copy() {
+        try {
+            return clone();
+        } catch (CloneNotSupportedException ex) {
+            LoggerFactory.getLogger(WebUIPlugin.class).error("Failed to copy web UI plugin descriptor", ex);
+            return new WebUIPlugin();
+        }
+    }
+
+    /** Retrieve a web UI plugin descriptor out of the contents of a "package.json".
+     * 
+     * @param obj a JSON object of the plugin description
+     * @return a web UI plugin descriptor out of the JSON object
+     * @throws PluginFormatException if the JSON text contains bad information, or not enough of it
+     */
+    public static WebUIPlugin fromPackageJSON(JSONObject obj) throws PluginFormatException {
+        try {
+            WebUIPlugin plugin = new WebUIPlugin();
+            plugin.name = obj.getString("name");
+            plugin.version = obj.optString("version", null);
+            plugin.description = obj.optString("description", null);
+
+            JSONObject objDicoogle = obj.getJSONObject("dicoogle");
+
+            plugin.slotId = objDicoogle.getString("slot-id");
+            plugin.moduleFile = objDicoogle.optString("module-file", "module.js");
+            plugin.caption = objDicoogle.optString("caption", null);
+            if (objDicoogle.containsKey("roles"))
+            {
+                JSONArray rolesArr = objDicoogle.getJSONArray("roles");
+
+                Set<String> roles = new HashSet<>();
+                if (rolesArr != null)
+                    for (Object role : rolesArr) {
+
+                        roles.add((String) role);
+                    }
+                plugin.roles = roles;
+            }
+
+            return plugin;
+        } catch(JSONException ex) {
+            throw new PluginFormatException(ex);
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getSlotId() {
+        return slotId;
+    }
+
+    public void setSlotId(String slotId) {
+        this.slotId = slotId;
+    }
+
+    public String getModuleFile() {
+        return moduleFile;
+    }
+
+    public void setModuleFile(String moduleFile) {
+        this.moduleFile = moduleFile;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setSettings(JSONObject holder) {
+        this.settings = holder;
+    }
+    
+    /** Getter for the plugin's settings.
+     * 
+     * @return a JSON object containing the settings, empty object if no settings are stored
+     */
+    public JSONObject getSettings() {
+        return this.settings != null ? this.settings : new JSONObject(false);
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+        
+    @Override
+    public String toString() {
+        return "WebUIPlugin{" + "name=" + name + ", description=" + description
+                + ", version=" + version + ", slotId=" + slotId
+                + ", moduleFile=" + moduleFile + ", enabled=" + enabled + '}';
+    }
+
+    public String getCaption() {
+        return caption;
+    }
+
+    public void setCaption(String caption) {
+        this.caption = caption;
+    }
+
+    public Set<String> getRoles() {
+        return roles;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPluginManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPluginManager.java
new file mode 100644
index 0000000..d51ab31
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/plugins/webui/WebUIPluginManager.java
@@ -0,0 +1,266 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.plugins.webui;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import net.sf.json.JSONObject;
+import net.sf.json.JSONSerializer;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+
+/** A class type for managing web UI plugins.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class WebUIPluginManager {
+    
+    private static final Logger logger = LoggerFactory.getLogger(WebUIPluginManager.class);
+
+    private static class WebUIEntry {
+        public final WebUIPlugin plugin;
+        public final String directory;
+        public final String zipPath;
+
+        public WebUIEntry(WebUIPlugin plugin, String directory, String zipPath) {
+            assert plugin != null;
+            assert directory != null;
+            this.plugin = plugin;
+            this.directory = directory;
+            this.zipPath = zipPath;
+        }
+        public WebUIEntry(WebUIPlugin plugin, String directory) {
+            this(plugin, directory, null);
+        }
+        public boolean isZipped() {
+            return this.zipPath != null;
+        }
+        public InputStream readFile(String file) throws IOException {
+            if (this.isZipped()) {
+                ZipFile zip = new ZipFile(this.zipPath);
+                return zip.getInputStream(zip.getEntry(this.directory + File.separatorChar + file));
+            } else {
+                File f = new File(this.directory + File.separatorChar + file);
+                return new FileInputStream(f);
+            }
+        }
+
+    }
+    
+    private final Map<String, WebUIEntry> plugins;
+    private final Set<WebUIPlugin> justPlugins;
+    
+    public WebUIPluginManager() {
+        this.plugins = new HashMap<>();
+        this.justPlugins = new HashSet<>();
+    }
+    
+    public void loadAll(File directory) {
+        assert directory != null;
+        if (!directory.exists()) {
+            logger.debug("No web plugins directory, ignoring");
+            return;
+        }
+        if (!directory.isDirectory()) {
+            logger.warn("Can't load web UI plugins, file {} is not a directory", directory);
+            return;
+        }
+        
+        for (File f : directory.listFiles()) {
+            if (!f.isDirectory()) continue;
+            try {
+                WebUIPlugin plugin = this.load(f);
+                logger.info("Loaded web plugin: {}", plugin.getName());
+            } catch (IOException ex) {
+                logger.error("Attempt to load plugin at {} failed", f.getName(), ex);
+            } catch (PluginFormatException ex) {
+                logger.warn("Could not load plugin at {} failed", f.getName(), ex);
+            }
+        }
+    }
+    
+    public WebUIPlugin load(File directory) throws IOException, PluginFormatException {
+        assert directory != null;
+        assert directory.isDirectory();
+        final String dirname = directory.getCanonicalPath();
+        File packageJSON = new File(dirname + File.separatorChar + "package.json");
+        try (BufferedReader reader = new BufferedReader(new FileReader(packageJSON))) {
+            String acc = "";
+            String line;
+            while ((line = reader.readLine()) != null) {
+                acc += line;
+            }
+            WebUIPlugin plugin = WebUIPlugin.fromPackageJSON((JSONObject)JSONSerializer.toJSON(acc));
+            File moduleFile = new File(directory.getAbsolutePath() + File.separatorChar + plugin.getModuleFile());
+            if (!moduleFile.canRead()) {
+                throw new IOException("Module file " + moduleFile.getName() + " cannot be read");
+            }
+            this.plugins.put(plugin.getName(), new WebUIEntry(plugin, dirname));
+            this.justPlugins.add(plugin);
+            return plugin;
+        }
+    }
+
+    /** Load all web plugins from a zip or jar file.
+     * @param pluginZip the zip file containing the plugins
+     * @throws java.io.IOException if the zip file can not be read
+     */
+    public void loadAllFromZip(ZipFile pluginZip) throws IOException {
+        assert pluginZip != null;
+        logger.trace("Discovering web UI plugins in {} ...", pluginZip.getName());
+        Pattern pckDescrMatcher = Pattern.compile("WebPlugins\\" + File.separatorChar + "(\\p{Alnum}|\\-|\\_)+\\" + File.separatorChar + "package.json");
+        Enumeration<? extends ZipEntry> entries = pluginZip.entries();
+        final int DIRNAME_TAIL = "/package.json".length();
+        while (entries.hasMoreElements()) {
+            ZipEntry e = entries.nextElement();
+            if (pckDescrMatcher.matcher(e.getName()).matches()) {
+                String dirname = e.getName().substring(0, e.getName().length() - DIRNAME_TAIL);
+                logger.info("Found web UI plugin in {} at \"{}\"", pluginZip.getName(), dirname);
+                try (BufferedReader reader = new BufferedReader(new InputStreamReader(pluginZip.getInputStream(e)))) {
+                    String acc = "";
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        acc += line;
+                    }
+                    WebUIPlugin plugin = WebUIPlugin.fromPackageJSON((JSONObject)JSONSerializer.toJSON(acc));
+                    this.plugins.put(plugin.getName(), new WebUIEntry(plugin, dirname, pluginZip.getName()));
+                    this.justPlugins.add(plugin);
+                } catch (PluginFormatException ex) {
+                    logger.warn("Failed to load plugin at \"{}\": {}", e.getName(), ex.getMessage());
+                }
+            }
+        }
+    }
+    
+    /** Get the descriptor of a web UI plugin.
+     * @param name the name of the plugin
+     * @return a copy of the installed web UI plugin
+     */
+    public WebUIPlugin get(String name) {
+        WebUIPlugin plugin = this.plugins.get(name).plugin;
+        return plugin == null ? null : plugin.copy();
+    }
+    
+    /** Retrieve and return the original JSON object of the plugin.
+     * @param name the name of the plugin
+     * @return a JSON object of the original "package.json"
+     * @throws IOException on error reading "package.json"
+     */
+    public JSONObject retrieveJSON(String name) throws IOException {
+        return retrieveJSON(readFile(name, "package.json"));
+    }
+    
+    /** Retrieve and return the original JSON object of the plugin.
+     * @param reader a reader providing the JSON object
+     * @return a JSON object of the original "package.json"
+     * @throws IOException on error reading "package.json"
+     */
+    private JSONObject retrieveJSON(Reader reader) throws IOException {
+        try (BufferedReader bufreader = new BufferedReader(reader)) {
+            String acc = "";
+            String line;
+            while ((line = bufreader.readLine()) != null) {
+                acc += line;
+            }
+            try {
+                return (JSONObject)JSONSerializer.toJSON(acc);
+            } catch (ClassCastException ex) {
+                throw new IOException("Not a JSON object", ex);
+            }
+        }
+    }
+
+    /** Retrieve and return the original JSON object of the plugin.
+     * @param istream an input stream providing the JSON object
+     * @return a JSON object of the original "package.json"
+     * @throws IOException on error reading "package.json"
+     */
+    private JSONObject retrieveJSON(InputStream istream) throws IOException {
+        return retrieveJSON(new InputStreamReader(istream));
+    }
+
+    public String retrieveModuleJS(String name) throws IOException {
+        String moduleFile = this.plugins.get(name).plugin.getModuleFile();
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(readFile(name, moduleFile)))) {
+            String acc = "";
+            String line;
+            while ((line = reader.readLine()) != null) {
+                acc += line + '\n';
+            }
+            return acc;
+        }
+    }
+
+    public Collection<WebUIPlugin> pluginSet() {
+        return Collections.unmodifiableSet(justPlugins);
+    }
+
+    public void loadSettings(File settingsFolder) {
+        for (WebUIPlugin plugin : pluginSet()) {
+            try {
+                File pluginSettingsFile = new File(settingsFolder.getPath() + File.separatorChar + plugin.getName() + ".json");
+                if (!pluginSettingsFile.exists()) {
+                    logger.info("Web plugin {} has no settings file", plugin.getName());
+                    continue;
+                }
+                BufferedReader reader = new BufferedReader(new FileReader(pluginSettingsFile));
+                String acc = "";
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    acc += line;
+                }
+                JSONObject settings = (JSONObject) JSONSerializer.toJSON(acc);
+                plugin.setSettings(settings);
+            } catch (IOException ex) {
+                logger.error("Failed to load web plugin settings", ex);
+            }
+        }
+    }
+
+    /** Read a file from an installed plugin's directory.
+     * 
+     * @param pluginName the name of the plugin
+     * @param filename the relative path of the file
+     * @return an input stream with the file's content
+     * @throws IOException if the file does not exist or can not be read
+     */
+    private InputStream readFile(String pluginName, String filename) throws IOException {
+        WebUIEntry e = this.plugins.get(pluginName);
+        if (e == null) {
+            throw new IllegalArgumentException("No such web UI plugin");
+        }
+        return e.readFile(filename);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeRMIClientSocketFactory.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeRMIClientSocketFactory.java
new file mode 100755
index 0000000..6842487
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeRMIClientSocketFactory.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package pt.ua.dicoogle.rGUI;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.Channel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.rmi.RMISecurityManager;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMISocketFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+ at Deprecated
+public class MultihomeRMIClientSocketFactory
+        implements RMIClientSocketFactory, Serializable {
+    private static final long serialVersionUID = 7033753601964541325L;
+
+    private final RMIClientSocketFactory factory;
+
+    public MultihomeRMIClientSocketFactory() {
+        this.factory = RMISocketFactory.getSocketFactory();
+       /* System.setProperty("java.security.policy","java.policy");
+        System.setProperty("java.rmi.server.codebase", "file:/c:/pluginClasses/");*/
+    }
+
+    @Override
+    public Socket createSocket(String hostString, int port) throws IOException {
+        //System.setProperty("java.security.policy", "my.policy");
+        final String[] hosts = hostString.split("!");
+        final int nhosts = hosts.length;
+        
+        if (nhosts < 2)
+            return factory().createSocket(hostString, port);
+
+        List<IOException> exceptions = new ArrayList<IOException>();
+        Selector selector = Selector.open();
+        for (String host : hosts) {
+            SocketChannel channel = SocketChannel.open();
+            channel.configureBlocking(false);
+            channel.register(selector, SelectionKey.OP_CONNECT);
+            SocketAddress addr = new InetSocketAddress(host, port);
+
+            try{
+                channel.connect(addr);
+            }catch(SocketException e){
+                //System.err.println("Sockect Exception: "+ e.getMessage() + ", Host: " + host + ", Port: "+ port);
+            }
+        }
+        SocketChannel connectedChannel = null;
+
+        connect:
+        while (true) {
+            if (selector.keys().isEmpty()) {
+                throw new IOException("Connection failed for " + hostString +
+                        ": " + exceptions);
+            }
+            selector.select();  // you can add a timeout parameter in millseconds
+            Set<SelectionKey> keys = selector.selectedKeys();
+            if (keys.isEmpty()) {
+                throw new IOException("Selection keys unexpectedly empty for " +
+                        hostString + "[exceptions: " + exceptions + "]");
+            }
+            for (SelectionKey key : keys) {
+                SocketChannel channel = (SocketChannel) key.channel();
+                key.cancel();
+                try {
+                    channel.configureBlocking(true);
+                    channel.finishConnect();
+                    connectedChannel = channel;
+                    break connect;
+                } catch (IOException e) {
+                    exceptions.add(e);
+                }
+            }
+        }
+
+        assert connectedChannel != null;
+
+        // Close the channels that didn't connect
+        for (SelectionKey key : selector.keys()) {
+            Channel channel = key.channel();
+            if (channel != connectedChannel)
+                channel.close();
+        }
+
+        final Socket socket = connectedChannel.socket();
+        if (factory == null && RMISocketFactory.getSocketFactory() == null)
+            return socket;
+
+        // We've determined that we can connect to this host but we didn't use
+        // the right factory so we have to reconnect with the factory.
+        String host = socket.getInetAddress().getHostAddress();
+        socket.close();
+        return factory().createSocket(host, port);
+    }
+
+    private RMIClientSocketFactory factory() {
+        if (factory != null)
+            return factory;
+        RMIClientSocketFactory f = RMISocketFactory.getSocketFactory();
+        if (f != null)
+            return f;
+        return RMISocketFactory.getDefaultSocketFactory();
+    }
+
+    // Thanks to "km" for the reminder that I need these:
+    @Override
+    public boolean equals(Object x) {
+        if (x.getClass() != this.getClass())
+            return false;
+        MultihomeRMIClientSocketFactory f = (MultihomeRMIClientSocketFactory) x;
+        return ((factory == null) ?
+                (f.factory == null) :
+                (factory.equals(f.factory)));
+    }
+
+    @Override
+    public int hashCode() {
+        int h = getClass().hashCode();
+        if (factory != null)
+            h += factory.hashCode();
+        return h;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeSslRMIClientSocketFactory.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeSslRMIClientSocketFactory.java
new file mode 100755
index 0000000..680d2fb
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/MultihomeSslRMIClientSocketFactory.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package pt.ua.dicoogle.rGUI;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.Channel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.rmi.RMISecurityManager;
+import java.rmi.server.RMIClientSocketFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+
+/**
+ * 
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class MultihomeSslRMIClientSocketFactory extends SslRMIClientSocketFactory
+        implements RMIClientSocketFactory, Serializable {
+    private static final long serialVersionUID = 11L;
+
+    //private final SslRMIClientSocketFactory factory;
+
+    public MultihomeSslRMIClientSocketFactory() {
+        super();
+    }
+
+    @Override
+    public Socket createSocket(String hostString, int port) throws IOException {
+        final String[] hosts = hostString.split("!");
+        final int nhosts = hosts.length;
+        
+        if (nhosts < 2)
+            return super.createSocket(hostString, port);
+
+        List<IOException> exceptions = new ArrayList<IOException>();
+
+        Selector selector = Selector.open();
+        
+        for (String host : hosts) {
+            SocketChannel channel = SocketChannel.open();
+            channel.configureBlocking(false);
+            channel.register(selector, SelectionKey.OP_CONNECT);
+            SocketAddress addr = new InetSocketAddress(host, port);
+            
+            
+            try{
+                channel.connect(addr);
+            }catch(SocketException e){
+                //System.err.println("Sockect Exception: "+ e.getMessage() + ", Host: " + host + ", Port: "+ port);
+            }
+        }
+        SocketChannel connectedChannel = null;
+
+        connect:
+        while (true) {
+            if (selector.keys().isEmpty()) {
+                throw new IOException("Connection failed for " + hostString +
+                        ": " + exceptions);
+            }
+            selector.select();  // you can add a timeout parameter in millseconds
+            Set<SelectionKey> keys = selector.selectedKeys();
+            if (keys.isEmpty()) {
+                throw new IOException("Selection keys unexpectedly empty for " +
+                        hostString + "[exceptions: " + exceptions + "]");
+            }
+            for (SelectionKey key : keys) {
+                SocketChannel channel = (SocketChannel) key.channel();
+                key.cancel();
+                try {
+                    channel.configureBlocking(true);
+                    channel.finishConnect();
+                    connectedChannel = channel;
+                    break connect;
+                } catch (IOException e) {
+                    exceptions.add(e);
+                }
+            }
+        }
+
+        assert connectedChannel != null;
+
+        // Close the channels that didn't connect
+        for (SelectionKey key : selector.keys()) {
+            Channel channel = key.channel();
+            if (channel != connectedChannel)
+                channel.close();
+        }
+
+        final Socket socket = connectedChannel.socket();
+
+        // We've determined that we can connect to this host but we didn't use
+        // the right factory so we have to reconnect with the factory.
+        String host = socket.getInetAddress().getHostAddress();
+        socket.close();
+        return super.createSocket(host, port);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/FileAction.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/FileAction.java
new file mode 100755
index 0000000..39a0b1f
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/FileAction.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+/**
+ * Class that defines an action to do when the file is selected
+ *
+ * This is an abstract class that needs to be implemented
+ * when RemoteFileBrowser is used.
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public abstract class FileAction{
+    
+    /**
+     * Defines an action to do when the file is choosed
+     * @param filePath
+     */
+    public abstract void setFileChoosed(String filePath);
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IRemoteFileSystem.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IRemoteFileSystem.java
new file mode 100755
index 0000000..3bc8601
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IRemoteFileSystem.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * This interface provides the main methods to browse a remote File System
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IRemoteFileSystem extends Remote {
+
+    //File createFileObject(String path) throws RemoteException;
+    //File createFileObject(File dir, String filename) throws RemoteException;
+    //File getChild(File parent, String fileName) throws RemoteException;
+    //boolean isFloppyDrive(File dir) throws RemoteException;
+    //File createNewFolder(File containingDir) throws RemoteException, IOException;
+    //Icon getSystemIcon(File f) throws RemoteException;
+
+
+    /**
+     * get FilePath from root to actualFile (One RemoteFile for each folder)
+     *
+     * @param filePath
+     * @return
+     * @throws RemoteException
+     */
+    RemoteFile[] getFilePath(String filePath) throws RemoteException;
+
+    RemoteFile[] getFiles(String dirPath, boolean useFileHiding) throws RemoteException;
+
+    boolean isFileSystemRoot(String dirPath) throws RemoteException;
+
+    boolean isFileSystem(String dirPath) throws RemoteException;
+
+    boolean isDrive(String dirPath) throws RemoteException;
+
+    boolean isRoot(String dirPath) throws RemoteException;
+
+    boolean isComputerNode(String dirPath) throws RemoteException;
+
+    RemoteFile getParentDirectory(String dirPath) throws RemoteException;
+
+    String getSystemDisplayName(String filePath) throws RemoteException;
+
+    String getSystemTypeDescription(String filePath) throws RemoteException;
+
+    RemoteFile getDefaultDirectory() throws RemoteException;
+
+    RemoteFile getHomeDirectory() throws RemoteException;
+
+    RemoteFile[] getRoots() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IconListRenderer.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IconListRenderer.java
new file mode 100755
index 0000000..25a86e7
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/IconListRenderer.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+import java.awt.Component;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.plaf.metal.MetalIconFactory;
+
+/**
+ * Icons Renderes to the Remote File Chooser
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class IconListRenderer extends DefaultListCellRenderer {
+
+    private Map<Object, Icon> icons = null;
+
+    public IconListRenderer() {
+        icons = new HashMap<Object, Icon>();
+
+        icons.put("file",
+                MetalIconFactory.getTreeLeafIcon());
+
+        icons.put("folder",
+                MetalIconFactory.getTreeFolderIcon());
+        icons.put("computer",
+                MetalIconFactory.getTreeComputerIcon());
+
+    }
+
+    @Override
+    public Component getListCellRendererComponent(
+            JList list, Object value, int index,
+            boolean isSelected, boolean cellHasFocus) {
+
+
+
+        // Get the renderer component from parent class
+        JLabel label =
+                (JLabel) super.getListCellRendererComponent(list,
+                value, index, isSelected, cellHasFocus);
+
+
+
+        RemoteFile file = (RemoteFile) value;
+        String type = "file";
+        
+        if(file != null && file.isDirectory())
+            type = "folder";
+
+        // Get icon to use for the list item value
+        Icon icon = icons.get(type);
+
+        // Set icon to display for value
+        label.setIcon(icon);
+
+        return label;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFile.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFile.java
new file mode 100755
index 0000000..df230f2
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFile.java
@@ -0,0 +1,181 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+import java.io.File;
+import java.io.Serializable;
+
+/**
+ * This Class represents one Remote File
+ * is useful to see the properties of a file
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class RemoteFile implements Serializable {
+    static final long serialVersionUID = 1L;
+
+    private String filePath;
+    private String name;
+    
+    private boolean canRead;
+    private boolean canWrite;
+    private boolean canExecute;
+
+    private boolean isDirectory;
+    private boolean isFile;
+    private boolean isHidden;
+
+    private long length;
+    
+
+    public RemoteFile(File file){
+        filePath = file.getAbsolutePath();
+        name = file.getName();
+
+        if(name.equals("") && System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1)
+        {
+            name = file.getPath();
+        }
+        else if(name.equals(""))
+            name = "/";
+
+
+        canRead = file.canRead();
+        canWrite = file.canWrite();
+        canExecute = file.canExecute();
+
+        isDirectory = file.isDirectory();
+        isFile = file.isFile();
+        isHidden = file.isHidden();
+
+        length = file.length();
+        
+    }
+
+    /**
+     *
+     * @return the current path of the remote file
+     */
+    public String getPath(){
+        return filePath;
+    }
+
+    /**
+     *
+     * @return the name of the remote file
+     */
+    public String getName(){
+        return name;
+    }
+
+    /**
+     *
+     * @return true if the server have the permitions to read the file
+     */
+    public boolean canRead(){
+        return canRead;
+    }
+
+    /**
+     *
+     * @return true if the server have the permitions to write in file
+     */
+    public boolean canWrite(){
+        return canWrite;
+    }
+
+    /**
+     *
+     * @return true if the server have the permitions to execute the file
+     */
+    public boolean canExecute(){
+        return canExecute;
+    }
+
+    /**
+     *
+     * @return true if the file is one directory
+     */
+    public boolean isDirectory(){
+        return isDirectory;
+    }
+
+    /**
+     *
+     * @return if the file is not a directory
+     */
+    public boolean isFile(){
+        return isFile;
+    }
+
+    /**
+     *
+     * @return true if the file is hidden
+     */
+    public boolean isHidden(){
+        return isHidden;
+    }
+
+    /**
+     *
+     * @return the file length (in bytes)
+     */
+    public long length(){
+        return length;
+    }
+
+    /**
+     *
+     * @return the name of the file
+     */
+    @Override
+    public String toString(){
+        return this.getName();
+    }
+
+    /**
+     * Test if the file is equals to another
+     * 
+     * @param other
+     * @return
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (other == null || other.getClass() != getClass()) {
+            return false;
+        }
+
+        if (other == this) {
+            return true;
+        }
+
+        RemoteFile tmp = (RemoteFile) other;
+
+        if (filePath.equals(tmp.filePath) && name.equals(tmp.name) && canRead == tmp.canRead
+                && canWrite == tmp.canWrite && canExecute == tmp.canExecute
+                && isDirectory == tmp.isDirectory && isFile == tmp.isFile
+                && isHidden == tmp.isHidden && length == tmp.length) {
+            return true;
+        }
+
+        return false;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.form
new file mode 100755
index 0000000..b065d63
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.form
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Look in:"/>
+      </Properties>
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[571, 320]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="34" max="-2" attributes="0"/>
+              <Component id="jComboBox" pref="274" max="32767" attributes="0"/>
+              <EmptySpace min="-2" pref="192" max="-2" attributes="0"/>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jTextFieldFilePath" pref="286" max="32767" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jButtonOpen" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
+              <Component id="jButtonCancel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jSeparator2" pref="539" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="1" attributes="0">
+                      <Group type="103" groupAlignment="1" attributes="0">
+                          <Group type="102" alignment="1" attributes="0">
+                              <Component id="jButtonUP" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                              <Component id="jButtonHome" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Component id="jSeparator1" alignment="1" pref="539" max="32767" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="475" max="32767" attributes="0"/>
+              <EmptySpace min="-2" pref="60" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonHome" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonUP" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jSeparator1" min="-2" pref="10" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="139" max="32767" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jSeparator2" min="-2" pref="10" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jTextFieldFilePath" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonOpen" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonCancel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Look in:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="jComboBox">
+      <Properties>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="0"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="popupMenuWillBecomeInvisible" listener="javax.swing.event.PopupMenuListener" parameters="javax.swing.event.PopupMenuEvent" handler="jComboBoxPopupMenuWillBecomeInvisible"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JSeparator" name="jSeparator1">
+    </Component>
+    <Component class="javax.swing.JSeparator" name="jSeparator2">
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="File Name:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextFieldFilePath">
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonOpen">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Open"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonOpenActionPerformed"/>
+      </Events>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListFiles">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+            <Property name="selectionMode" type="int" value="0"/>
+            <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
+              <Color id="Default Cursor"/>
+            </Property>
+            <Property name="doubleBuffered" type="boolean" value="true"/>
+            <Property name="layoutOrientation" type="int" value="1"/>
+          </Properties>
+          <Events>
+            <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jListFilesMouseClicked"/>
+            <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="jListFilesValueChanged"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonCancel">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Cancel"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonCancelActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonUP">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="UP"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonUPActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonHome">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Home"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonHomeActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.java
new file mode 100755
index 0000000..76cd6f6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileChooser.java
@@ -0,0 +1,372 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.rmi.RemoteException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.plaf.metal.MetalIconFactory;
+
+/**
+ * Remote File Chooser window
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class RemoteFileChooser extends javax.swing.JFrame {
+
+    public static final int APPROVED = 1;
+    public static final int CANCELED = 2;
+    public static final int DIRECTORIES_ONLY = 3;
+    
+    private IRemoteFileSystem rFS;
+    private String actualPath;
+    private int mode;
+    private FileAction act;
+    private boolean created = false;
+
+    /** Creates new form FileChooser */
+    public RemoteFileChooser(IRemoteFileSystem rFS, String homePath, FileAction action) {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        jButtonUP.setIcon(MetalIconFactory.getFileChooserUpFolderIcon());
+        jButtonHome.setIcon(MetalIconFactory.getFileChooserHomeFolderIcon());
+
+        jListFiles.setCellRenderer(new IconListRenderer());
+        jComboBox.setRenderer(new IconListRenderer());
+
+        if (homePath == null) {
+            homePath = ".";
+        }
+
+        this.rFS = rFS;
+        actualPath = homePath;
+
+        mode = 0;
+
+        loadFiles();
+
+        created = true;
+
+        act = action;
+    }
+
+    /**
+     * Load Files to JListFiles
+     */
+    private void loadFiles() {
+        try {
+            refreshComboBox();
+
+            RemoteFile[] files = rFS.getFiles(actualPath, false);
+            DefaultListModel list = new DefaultListModel();
+
+            for (int i = 0; i < files.length; i++) {
+                if (mode == 0 || (mode == DIRECTORIES_ONLY && files[i].isDirectory())) {
+                    list.addElement(files[i]);
+                }
+            }
+
+            // (files.length + 1) / 2 - to round up
+            jListFiles.setVisibleRowCount((files.length + 1) / 2);
+
+            jListFiles.setModel(list);
+
+            jTextFieldFilePath.setText(actualPath);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(RemoteFileChooser.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    private void refreshComboBox() {
+        try {
+            jComboBox.removeAllItems();
+            RemoteFile[] rFiles = rFS.getFilePath(actualPath);
+            RemoteFile tmp;
+            int i;
+
+            // invert the list order
+            for (i = 0; i < rFiles.length / 2; i++) {
+                tmp = rFiles[i];
+                rFiles[i] = rFiles[rFiles.length - 1 - i];
+                rFiles[rFiles.length - 1 - i] = tmp;
+            }
+
+            for (i = 0; i < rFiles.length; i++) {
+                jComboBox.insertItemAt(rFiles[i], i);
+            }
+
+            jComboBox.setSelectedIndex(rFiles.length - 1);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(RemoteFileChooser.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void setFileSelectionMode(int mode) {
+        if (mode == DIRECTORIES_ONLY) {
+            this.mode = mode;
+        }
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel2 = new javax.swing.JLabel();
+        jLabel1 = new javax.swing.JLabel();
+        jComboBox = new javax.swing.JComboBox();
+        jSeparator1 = new javax.swing.JSeparator();
+        jSeparator2 = new javax.swing.JSeparator();
+        jLabel3 = new javax.swing.JLabel();
+        jTextFieldFilePath = new javax.swing.JTextField();
+        jButtonOpen = new javax.swing.JButton();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jListFiles = new javax.swing.JList();
+        jButtonCancel = new javax.swing.JButton();
+        jButtonUP = new javax.swing.JButton();
+        jButtonHome = new javax.swing.JButton();
+
+        jLabel2.setText("Look in:");
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setMinimumSize(new java.awt.Dimension(571, 320));
+
+        jLabel1.setText("Look in:");
+
+        jComboBox.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
+            public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent evt) {
+            }
+            public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {
+                jComboBoxPopupMenuWillBecomeInvisible(evt);
+            }
+            public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
+            }
+        });
+
+        jLabel3.setText("File Name:");
+
+        jButtonOpen.setText("Open");
+        jButtonOpen.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonOpenActionPerformed(evt);
+            }
+        });
+
+        jListFiles.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+        jListFiles.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
+        jListFiles.setDoubleBuffered(true);
+        jListFiles.setLayoutOrientation(javax.swing.JList.VERTICAL_WRAP);
+        jListFiles.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jListFilesMouseClicked(evt);
+            }
+        });
+        jListFiles.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
+                jListFilesValueChanged(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jListFiles);
+
+        jButtonCancel.setText("Cancel");
+        jButtonCancel.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonCancelActionPerformed(evt);
+            }
+        });
+
+        jButtonUP.setText("UP");
+        jButtonUP.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonUPActionPerformed(evt);
+            }
+        });
+
+        jButtonHome.setText("Home");
+        jButtonHome.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonHomeActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel1)
+                .add(34, 34, 34)
+                .add(jComboBox, 0, 274, Short.MAX_VALUE)
+                .add(192, 192, 192))
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel3)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jTextFieldFilePath, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 286, Short.MAX_VALUE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jButtonOpen)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jButtonCancel)
+                .addContainerGap())
+            .add(layout.createSequentialGroup()
+                .add(12, 12, 12)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createSequentialGroup()
+                        .add(jSeparator2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 539, Short.MAX_VALUE)
+                        .addContainerGap())
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                            .add(layout.createSequentialGroup()
+                                .add(jButtonUP)
+                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                                .add(jButtonHome))
+                            .add(jSeparator1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 539, Short.MAX_VALUE))
+                        .add(20, 20, 20))))
+            .add(layout.createSequentialGroup()
+                .add(36, 36, 36)
+                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 475, Short.MAX_VALUE)
+                .add(60, 60, 60))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(17, 17, 17)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel1)
+                    .add(jComboBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                    .add(jButtonHome)
+                    .add(jButtonUP))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jSeparator1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 139, Short.MAX_VALUE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jSeparator2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel3)
+                    .add(jTextFieldFilePath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                    .add(jButtonOpen)
+                    .add(jButtonCancel))
+                .add(40, 40, 40))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jListFilesValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListFilesValueChanged
+        if (!jListFiles.isSelectionEmpty()) {
+            RemoteFile file = (RemoteFile) jListFiles.getSelectedValue();
+            jTextFieldFilePath.setText(file.getPath());
+        }
+    }//GEN-LAST:event_jListFilesValueChanged
+
+    private void jButtonUPActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonUPActionPerformed
+        try {
+            if (!rFS.isFileSystemRoot(actualPath)) {
+                RemoteFile file = rFS.getParentDirectory(actualPath);
+
+                if(file != null){
+                    actualPath = file.getPath();
+
+                    loadFiles();
+                }
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(RemoteFileChooser.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonUPActionPerformed
+
+    private void jListFilesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListFilesMouseClicked
+        if (evt.getClickCount() == 2) {
+            RemoteFile file = (RemoteFile) jListFiles.getSelectedValue();
+            if (file.isDirectory()) {
+                actualPath = file.getPath();
+                loadFiles();
+            }
+        }
+    }//GEN-LAST:event_jListFilesMouseClicked
+
+    private void jButtonOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonOpenActionPerformed
+        if (act != null && jTextFieldFilePath.getText() != null) {
+            act.setFileChoosed(jTextFieldFilePath.getText());
+        }
+
+        this.dispose();
+    }//GEN-LAST:event_jButtonOpenActionPerformed
+
+    private void jButtonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCancelActionPerformed
+        this.dispose();
+    }//GEN-LAST:event_jButtonCancelActionPerformed
+
+    private void jComboBoxPopupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent evt) {//GEN-FIRST:event_jComboBoxPopupMenuWillBecomeInvisible
+        try {
+            int index = jComboBox.getSelectedIndex();
+            RemoteFile[] rFiles = rFS.getFilePath(actualPath);
+            actualPath = rFiles[rFiles.length - 1 - index].getPath();
+
+            loadFiles();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(RemoteFileChooser.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jComboBoxPopupMenuWillBecomeInvisible
+
+    private void jButtonHomeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonHomeActionPerformed
+        try {
+            if (!rFS.isFileSystemRoot(actualPath)) {
+                RemoteFile file = rFS.getHomeDirectory();
+                actualPath = file.getPath();
+
+                loadFiles();
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(RemoteFileChooser.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonHomeActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonCancel;
+    private javax.swing.JButton jButtonHome;
+    private javax.swing.JButton jButtonOpen;
+    private javax.swing.JButton jButtonUP;
+    private javax.swing.JComboBox jComboBox;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JList jListFiles;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JSeparator jSeparator2;
+    private javax.swing.JTextField jTextFieldFilePath;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileSystemServer.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileSystemServer.java
new file mode 100755
index 0000000..bff35a5
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/RFileBrowser/RemoteFileSystemServer.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.RFileBrowser;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.filechooser.FileSystemView;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class RemoteFileSystemServer implements IRemoteFileSystem {
+
+    private FileSystemView fs = FileSystemView.getFileSystemView();
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static RemoteFileSystemServer instance = null;
+
+    public static synchronized RemoteFileSystemServer getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new RemoteFileSystemServer();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(RemoteFileSystemServer.class).error(ex.getMessage(), ex);
+        }
+
+        return instance;
+    }
+
+    private RemoteFileSystemServer(){
+        
+    }
+
+    /**
+     * get FilePath from root to actualFile (One RemoteFile for each folder)
+     *
+     * @param filePath
+     * @return
+     */
+    @Override
+    public RemoteFile[] getFilePath(String filePath) {
+        if(filePath == null || filePath.equals(""))
+            filePath = ".";
+
+        ArrayList<RemoteFile> files = new ArrayList<RemoteFile>();
+        RemoteFile rFile;
+
+        File file = new File(filePath);
+        rFile = new RemoteFile(file);
+
+        if(file.isDirectory())
+            files.add(rFile);
+
+        while(rFile != null && !isRoot(rFile.getPath())){
+            rFile = getParentDirectory(rFile.getPath());
+
+            if (rFile != null)
+                files.add(rFile);
+        }
+
+        if(System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1)
+        {
+            File[] roots = File.listRoots();
+            
+            for(File f: roots)
+                if(f.exists())
+                    files.add(new RemoteFile(f));
+        }
+
+        RemoteFile[] rFilesArray = new RemoteFile[files.size()];
+        return files.toArray(rFilesArray);
+    }
+
+    @Override
+    public RemoteFile[] getFiles(String dirPath, boolean useFileHiding) {
+        if(dirPath == null || dirPath.equals(""))
+            dirPath = ".";
+
+
+        File dir = new File(dirPath);
+        
+        if (!dir.exists())
+           dir = new File(".");
+        
+        File[] file = fs.getFiles(dir, useFileHiding);
+
+        
+        RemoteFile[] remoteFile = new RemoteFile[file.length];
+
+        for(int i = 0; i < file.length; i++)
+            remoteFile[i] = new RemoteFile(file[i]);
+
+        return remoteFile;
+    }
+
+    @Override
+    public boolean isFileSystemRoot(String dirPath) {
+        File dir = new File(dirPath);
+
+        if (!dir.exists())
+           return false;
+        
+        return fs.isFileSystemRoot(dir);
+    }
+
+    @Override
+    public boolean isRoot(String dirPath){
+        File dir = new File(dirPath);
+
+        if (!dir.exists())
+           return false;
+
+        return fs.isRoot(dir);
+    }
+
+    @Override
+    public boolean isFileSystem(String dirPath) {
+        File f = new File(dirPath);
+
+        if (!f.exists())
+           return false;
+
+        return fs.isFileSystem(f);
+    }
+
+    @Override
+    public boolean isDrive(String dirPath) {
+        File dir = new File(dirPath);
+
+        return fs.isDrive(dir);
+    }
+
+    @Override
+    public boolean isComputerNode(String dirPath) {
+        File dir = new File(dirPath);
+
+        if (!dir.exists())
+           dir = new File(".");
+        
+        return fs.isComputerNode(dir);
+    }
+
+    @Override
+    public RemoteFile getParentDirectory(String dirPath) {
+        File dir = new File(dirPath);
+        
+        if (!dir.exists())
+           dir = new File(".");
+        
+        if (fs.isRoot(dir))
+            return null;
+
+        if(System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1){
+            if(dir.getAbsolutePath().lastIndexOf('\\') == (dir.getAbsolutePath().length()-1) )
+                return null;
+        }
+        
+        File parent = fs.getParentDirectory(dir);
+
+        if(parent != null)
+            return new RemoteFile(parent);
+
+        return null;
+    }
+
+    @Override
+    public String getSystemDisplayName(String filePath) {
+        File f = new File(filePath);
+
+        return fs.getSystemDisplayName(f);
+    }
+
+    @Override
+    public String getSystemTypeDescription(String filePath) {
+        File f = new File(filePath);
+
+        return fs.getSystemTypeDescription(f);
+    }
+
+    @Override
+    public RemoteFile getDefaultDirectory() {
+        return new RemoteFile(fs.getDefaultDirectory());
+    }
+
+    @Override
+    public RemoteFile getHomeDirectory() {
+        return new RemoteFile(fs.getHomeDirectory());
+    }
+
+    @Override
+    public RemoteFile[] getRoots() {
+        File[] file = fs.getRoots();
+
+        RemoteFile[] remoteFile = new RemoteFile[file.length];
+
+        for(int i = 0; i < file.length; i++)
+            remoteFile[i] = new RemoteFile(file[i]);
+
+        return remoteFile;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/AdminRefs.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/AdminRefs.java
new file mode 100755
index 0000000..ede5fd7
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/AdminRefs.java
@@ -0,0 +1,357 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.interfaces.IAdmin;
+import pt.ua.dicoogle.rGUI.RFileBrowser.IRemoteFileSystem;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IAccessList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IActiveSessions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDirectory;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IIndexOptions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ILogs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.INetworkInterfaces;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPendingMessages;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQRServers;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQueryRetrieve;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISOPClass;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IServices;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IStartupServ;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ITaskList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IUsersManager;
+
+/**
+ * Esta classe é responsável por ir buscar as referências para os objectos remotos da administração
+ * e guardar as referências para esses objectos
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class AdminRefs {
+
+    private ILogs logs;
+    private IQRServers qrservers;
+    private IServices services;
+    private IStartupServ startupServ;
+    private IQueryRetrieve queryRetrieve;
+    private IAccessList accessList;
+    private IIndexOptions indexOptions;
+    private ISOPClass sopClass;
+    private IDirectory directorySettings;
+    private IUsersManager usersManager;
+    private IActiveSessions activeSessions;
+    private ITaskList taskList;
+    private IPendingMessages pendingMessages;
+    private IAdmin admin;
+    private INetworkInterfaces networkInterfaces;
+    private IPluginControllerAdmin pluginController;
+
+    private static AdminRefs instance;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized AdminRefs getAdminRefs(final IAdmin admin) {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new AdminRefs(admin);
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    public static AdminRefs getInstance() {
+        return instance;
+    }
+
+    private AdminRefs(IAdmin admin) {
+        this.admin = admin;
+
+        getRefs();
+    }
+
+    /**
+     * This function is responsible for obtaining references to Remote administration objects
+     */
+    private void getRefs() {
+        class GetReferences {
+
+            public void run() {
+                try {
+                    //System.out.println("Starting to adquire Admin Refs");
+
+                    
+                    qrservers = admin.getQRServers();
+                    logs = admin.getLogs();
+                    services = admin.getServices();
+                    startupServ = admin.getStartupServ();
+                    queryRetrieve = admin.getQueryRetrive();
+                    accessList = admin.getAccessList();
+                    indexOptions = admin.getIndexOptions();
+                    sopClass = admin.getSOPClass();
+                    directorySettings = admin.getDirectorySettings();
+                    usersManager = admin.getUsersManager();
+                    activeSessions = admin.getActiveSessions();
+                    taskList = admin.getTaskList();
+                    pendingMessages = admin.getPendingMessages();
+                    networkInterfaces = admin.getNetworkInterface();
+                    pluginController = admin.getPluginController();
+                    
+                    //System.out.println("Admin Refs Adquired");
+                } catch (RemoteException ex) {
+                    LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+
+                    //TODO: se falhar, ter?? implica????es... o programa cliente deve parar
+                }
+            }
+        }
+        GetReferences getRefs = new GetReferences();
+
+        //starts the Thread that will get the remote administrations object references
+        getRefs.run();
+    }
+
+    /**
+     * @return the logs
+     */
+    public ILogs getLogs() {
+        return logs;
+    }
+
+    /**
+     * @return the qrservers
+     */
+    public IQRServers getQRservers() {
+        return qrservers;
+    }
+
+    /**
+     * @return the services
+     */
+    public IServices getServices() {
+        return services;
+    }
+
+    /**
+     * @return the startup Services
+     */
+    public IStartupServ getStartupServices() {
+        return startupServ;
+    }
+
+    /**
+     * @return the QueryRetrieve configuration object reference
+     */
+    public IQueryRetrieve getQueryRetrieve() {
+        return queryRetrieve;
+    }
+
+    /**
+     * @return the Access List configuration object reference
+     */
+    public IAccessList getAccessList() {
+        return accessList;
+    }
+
+    /**
+     * @return the IndexOptions configuration object reference
+     */
+    public IIndexOptions getIndexOptions() {
+        return indexOptions;
+    }
+
+    /**
+     * @return the IndexOptions configuration object reference
+     */
+    public ISOPClass getSOPClass() {
+        return sopClass;
+    }
+
+    /**
+     * @return the Directory Settings configuration object reference
+     */
+    public IDirectory getDirectorySettings() {
+        return directorySettings;
+    }
+
+    /**
+     *
+     * @return the UsersManager object reference
+     */
+    public IUsersManager getUsersManager(){
+        return usersManager;
+    }
+
+    /**
+     *
+     * @return the ActiveSessions object reference
+     */
+    public IActiveSessions getActiveSessions(){
+        return activeSessions;
+    }
+
+    /**
+     *
+     * @return the Pending Messages object reference
+     */
+    public IPendingMessages getPendingMessages(){
+        return pendingMessages;
+    }
+
+
+    public INetworkInterfaces getNetworkInterfaces()
+    {
+        return networkInterfaces;
+    }
+
+
+    /**
+     * Logout Admin from serv
+     *
+     * @return true if logout succeeded
+     */
+    public boolean logout() {
+        try {
+            admin.logout();
+
+            return true;
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+
+            return false;
+        }
+    }
+
+    public boolean saveSettings(){
+        try {
+            admin.saveSettings();
+
+            return true;
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+
+            return false;
+        }
+    }
+    public boolean unsavedSettings(){
+        try {
+            return admin.unsavedSettings();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+        return false;
+    }
+
+    public IRemoteFileSystem getRFS(){
+        try {
+            return admin.getRFS();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+        
+        return null;
+    }
+
+    public String getDefaultFilePath(){
+        try {
+            return admin.getDefaultFilePath();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+
+        return null;
+    }
+
+    /**
+     * Index new file or folder
+     *
+     * @param Path - file or folter path
+     */
+    public void index(String Path, boolean resume){
+        try {
+            indexOptions.index(Path, resume);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Re-Index one file
+     *
+     * @param Path - file or folter path
+     */
+    public void reIndex(ArrayList<String> list){
+        try {
+            indexOptions.reIndex(list);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+
+    public void shutdownServer(){
+        try {
+            admin.shutdownServer();
+        } catch (RemoteException ex) {
+            //LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+        }
+        //System.out.println("The server is Shutting Down");
+    }
+
+    /**
+     * @return the taskList
+     */
+    public ITaskList getTaskList() {
+        return taskList;
+    }
+
+    public IPluginControllerAdmin getPluginController()
+    {
+        return pluginController;
+    }
+
+       /*
+     * Attention, we should not pass paths directly as arguments 
+     * we should instead use a datasource, since the file can be stored somewhere else
+     * or even in memory...
+     * 
+     */
+    public void cbirIndex(String path) {
+        //a list containing all indexation plugins
+        if(pluginController == null) return;
+
+        //try{
+            //pluginController.cbirIndex(path);
+        //}
+       /* catch(RemoteException e){
+            System.err.println("Oh dear...");
+            System.err.println(e);
+        }*/
+    }    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ClientCore.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ClientCore.java
new file mode 100755
index 0000000..132dfaa
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ClientCore.java
@@ -0,0 +1,257 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.rGUI.client.UIHelper.ServerMessagesManager;
+import pt.ua.dicoogle.rGUI.client.windows.MainWindow;
+import pt.ua.dicoogle.rGUI.interfaces.IAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+
+public class ClientCore {
+
+    private IUser user = null;
+    private IAdmin admin = null;
+
+    private InetAddress serverAddr;
+    private boolean localServer = false;
+
+    private static int timeoutTime = 8000;  //5 seconds (needs to be minor than 15 seconds)
+    private static int startTime = 1000;    //starts the keepAlive only 1 second after start
+    
+    private AdminKeepAliveThread adminKeep;
+    private UserKeepAliveThread userKeep;
+    
+    private static ClientCore instance;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized ClientCore getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new ClientCore();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private ClientCore() {
+      
+    }
+
+    public void setUser(IUser user) {
+        try {
+            this.user = user;
+
+            if(Main.isFixedClient())
+                user.shtudownTimeout(Main.randomInteger);
+            if (!(Main.isFixedClient() && user.shtudownTimeout(Main.randomInteger))) {
+                userKeep = new UserKeepAliveThread(user);
+                userKeep.start();
+            }
+
+    
+            
+                //userKeep = new UserKeepAliveThread(user);
+                //userKeep.start();
+
+            
+            UserRefs.getUserRefs(user);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public boolean isUser() {
+        return user != null;
+    }
+
+    public IUser getUser() {
+        return user;
+    }
+
+    public void setAdmin(IAdmin admin) {
+        try {
+            this.admin = admin;
+            
+            if(Main.isFixedClient())
+                admin.shtudownTimeout(Main.randomInteger);
+            if (!(Main.isFixedClient() && admin.shtudownTimeout(Main.randomInteger))) {
+                adminKeep = new AdminKeepAliveThread(admin);
+                adminKeep.start();
+            }
+
+            AdminRefs.getAdminRefs(admin);          
+            ServerMessagesManager.getInstance();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public boolean isAdmin() {
+        return AdminRefs.getInstance() != null;
+    }
+
+    public void setServerAddress(InetAddress serverAddr){
+        this.serverAddr = serverAddr;
+
+        try {
+            //Verify if the remote server is in the local pc
+            if (serverAddr.equals(InetAddress.getByName("localhost"))){
+                System.out.println(" localServer True");
+                localServer = true;
+                return;
+            }
+            
+            InetAddress in = InetAddress.getLocalHost();
+            InetAddress[] all = InetAddress.getAllByName(in.getHostName());
+            
+            for (int i = 0; i < all.length; i++)
+                if (serverAddr.equals(all[i])){
+                    localServer = true;
+                    return;
+                }
+            System.out.println(" localServer False");
+            localServer = false;
+        } catch (UnknownHostException ex) {
+            //LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public InetAddress getServerAddress(){
+        return serverAddr;
+    }
+    
+    public boolean isLocalServer(){        
+        return localServer;
+    }
+
+    public void stopKeepAlives(){
+        //DebugManager.getInstance().log("Stopping KeepAlive messages between server and client");
+        if(isAdmin() && adminKeep != null){
+            adminKeep.timer.cancel();
+            adminKeep = null;
+        }
+
+        if(userKeep != null){
+            userKeep.timer.cancel();
+            userKeep = null;
+        }
+    }
+
+    private void closeDicoogle(int source) {
+        String message = "The connection with the GUI server is lost!\n";
+        
+        if(source == 1)
+            message += "User KeepAlive failed.\n";
+        else
+            message += "Admin KeepAlive failed.\n";
+
+        message += "Dicoolge client is closing.";
+        
+        JOptionPane.showMessageDialog(MainWindow.getInstance(), message,
+                "Connection Lost", JOptionPane.ERROR_MESSAGE);
+
+        System.exit(2);
+    }
+
+    /**
+     * Private classes, they are used only within this parent class
+     */
+   
+
+    private class UserKeepAliveThread extends Thread{
+        private Timer timer;
+        private TimerTask userTask;
+        private IUser userRef;
+
+        public UserKeepAliveThread(IUser user){
+            timer = new Timer();
+            userRef = user;
+        }
+
+        @Override
+        public void run(){
+            userTask = new UserKeepAlive();
+            timer.schedule(userTask, startTime, timeoutTime);
+        }
+
+        private class UserKeepAlive extends TimerTask {
+
+            @Override
+            public void run() {
+                try {
+                    userRef.KeepAlive();
+                } catch (Exception ex) {
+                    closeDicoogle(1);
+                }
+            }
+        }
+    }
+
+    private class AdminKeepAliveThread extends Thread{
+        private Timer timer;
+        private TimerTask adminTask;
+        private IAdmin adminRef;
+
+        public AdminKeepAliveThread(IAdmin admin){
+            timer = new Timer();
+            adminRef = admin;
+        }
+
+
+        @Override
+        public void run(){
+            adminTask = new AdminKeepAlive();
+            timer.schedule(adminTask, startTime, timeoutTime);
+        }
+
+        private class AdminKeepAlive extends TimerTask {
+
+            @Override
+            public void run() {
+                try {
+                    adminRef.KeepAlive();
+                } catch (Exception ex) {
+                    closeDicoogle(2);
+                }
+            }
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ConnectServer.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ConnectServer.java
new file mode 100755
index 0000000..7ed21b4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/ConnectServer.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client;
+
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.rGUI.MultihomeSslRMIClientSocketFactory;
+import pt.ua.dicoogle.rGUI.client.windows.ConnectWindow;
+import pt.ua.dicoogle.rGUI.client.windows.MainWindow;
+import pt.ua.dicoogle.rGUI.client.UIHelper.TrayIconCreator;
+
+import pt.ua.dicoogle.rGUI.interfaces.ILogin;
+import pt.ua.dicoogle.rGUI.interfaces.IAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+import pt.ua.dicoogle.utils.KeysManager;
+
+/**
+ * This class is responsible for making the connection to the RMI GUI Server
+ *
+ * After the connection, the user can login to manage the server or to search
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class ConnectServer {
+    private String host;
+    private int port;
+    private ILogin login;
+    private Registry reg;
+    private ClientCore core;
+
+    /*
+     * Falta propagar uma excepção que indique uma falha na conexão
+     */
+    public ConnectServer(String host, int port) throws RemoteException, NotBoundException, UnknownHostException{
+        this.host = host;
+        this.port = port;
+        
+        System.out.println("Host: "+host);
+        System.out.println("Port: " + port);
+        
+        String TrustStorePath = KeysManager.getClientKeyPath();
+
+        //define the System property to use a SSL TrustStore
+        System.setProperty("javax.net.ssl.trustStore", TrustStorePath);
+
+        if (Main.isFixedClient())
+        {
+            
+            String keyStorePath = KeysManager.getServerKeyPath();
+
+            //define the System properties to use a SSLKeystore
+            System.setProperty("javax.net.ssl.keyStore", keyStorePath);
+            System.setProperty("javax.net.ssl.keyStorePassword", "dicooglepacs");
+        }
+
+        System.setProperty("sun.rmi.activation.execTimeout", "200");
+        
+
+        //get the Registry with the Remote Objects
+        reg = LocateRegistry.getRegistry(this.host, this.port, new MultihomeSslRMIClientSocketFactory());
+        //reg = LocateRegistry.getRegistry(this.host, this.port);
+        
+
+        login = (ILogin) reg.lookup("login");
+
+        
+        
+ 
+        core = ClientCore.getInstance();
+
+        InetAddress serverAddr = InetAddress.getByName(host);
+            
+        core.setServerAddress(serverAddr);
+        
+    }
+    
+    /**
+     * Try to login (Administration and UserSearch) in server
+     *
+     * @param username
+     * @param pass
+     */
+    public boolean login(String username, String passwordHash) throws RemoteException{
+            
+            IAdmin admin = loginAdmin(username, passwordHash);
+            IUser user;
+
+            // if the user is administrator, automactly get the user
+            if(admin != null){
+                core.setAdmin(admin);
+                user = admin.getUser();
+            }
+            else
+                user = loginUser(username, passwordHash);
+
+            if(user != null)
+                core.setUser(user);
+
+
+            if(admin == null && user == null)
+                return false;
+            
+        TrayIconCreator.getInstance();
+
+        MainWindow.getInstance().setVisible(true);
+
+        ConnectWindow.getInstance().setVisible(false);
+        
+        MainWindow.getInstance().toFront();
+        return true;
+    }
+
+    /**
+     *
+     * @param username
+     * @param pass
+     * @return the reference to the administration main object
+     * @throws RemoteException
+     */
+    private IAdmin loginAdmin(String username, String pass) throws RemoteException{
+        if (login != null)
+            return login.LoginAdmin(username, pass);
+        
+        return null;
+    }
+
+    /**
+     *
+     * @param username
+     * @param pass
+     * @return the reference to the user search main object
+     * @throws RemoteException
+     */
+    private IUser loginUser(String username, String pass) throws RemoteException{
+        if (login != null)
+            return login.LoginUser(username, pass);
+        
+        return null;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/AllowBlankMaskFormatter.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/AllowBlankMaskFormatter.java
new file mode 100755
index 0000000..fa5fc6a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/AllowBlankMaskFormatter.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Getted from
+ * http://www.javalobby.org/java/forums/t48652.html
+ */
+
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.text.ParseException;
+
+import javax.swing.text.MaskFormatter;
+
+/**
+ * A special version of the {@link javax.swing.text.MaskFormatter} for
+ * {@link javax.swing.JFormattedTextField formatted text fields} that supports
+ * the field being emptied/left blank.
+ *
+ * @author R.J. Lorimer
+ * @author Luis Silva
+ */
+ at Deprecated
+public class AllowBlankMaskFormatter extends MaskFormatter {
+
+	private boolean allowBlankField = true;
+	private String blankRepresentation;
+
+	public AllowBlankMaskFormatter() {
+		super();
+	}
+	public AllowBlankMaskFormatter(String mask) throws ParseException {
+		super(mask);
+	}
+
+	public void setAllowBlankField(boolean allowBlankField) {
+		this.allowBlankField = allowBlankField;
+	}
+
+	public boolean isAllowBlankField() {
+		return allowBlankField;
+	}
+
+	/**
+	 * Update our blank representation whenever the mask is updated.
+	 */
+	@Override public void setMask(String mask) throws ParseException {
+		super.setMask(mask);
+		updateBlankRepresentation();
+	}
+
+	/**
+	 * Update our blank representation whenever the mask is updated.
+	 */
+	@Override public void setPlaceholderCharacter(char placeholder) {
+		super.setPlaceholderCharacter(placeholder);
+		updateBlankRepresentation();
+	}
+
+	/**
+	 * Override the stringToValue method to check the blank representation.
+	 */
+	@Override public Object stringToValue(String value) throws ParseException {
+		Object result = value;
+		if(isAllowBlankField() && blankRepresentation != null && blankRepresentation.equals(value)) {
+			// an empty field should have a 'null' value.
+			result = null;
+		}
+		else {
+			result = super.stringToValue(value);
+		}
+		return result;
+	}
+
+	private void updateBlankRepresentation() {
+		try {
+			// calling valueToString on the parent class with a null attribute will get the 'blank'
+			// representation.
+			blankRepresentation = valueToString(null);
+		}
+		catch(ParseException e) {
+			blankRepresentation = null;
+		}
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/DisplayJAI.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/DisplayJAI.java
new file mode 100755
index 0000000..40fd1d3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/DisplayJAI.java
@@ -0,0 +1,159 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+/*
+ * %W% %E% %U%
+ *
+ * Copyright (c) 2000 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
+ * modify and redistribute this software in source and binary code form,
+ * provided that i) this copyright notice and license appear on all copies of
+ * the software; and ii) Licensee does not utilize the software in a manner
+ * which is disparaging to Sun.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
+ * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
+ * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
+ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
+ * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * This software is not designed or intended for use in on-line control of
+ * aircraft, air traffic, aircraft navigation or aircraft communications; or in
+ * the design, construction, operation or maintenance of any nuclear
+ * facility. Licensee represents and warrants that it will not use or
+ * redistribute the Software for such purposes.
+ */
+
+/**
+ *  Example display class Swing Component that is able
+ *  to contain an image.  The size of the image
+ *  and size of the container can be different.
+ *  The image can be positioned within the
+ *  container.  This class extends JPanel in order
+ *  to support layout management.  Tiling is supported
+ *  as of JDK1.3 via drawRenderedImage().
+ *
+ *  @author Dennis Sigel
+ *
+ *  @see javax.swing.JPanel
+ *  @see javax.swing.JComponent
+ *  @see java.awt.image.RenderedImage
+ */
+
+
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Dimension;
+import java.awt.geom.AffineTransform;
+import java.awt.image.RenderedImage;
+import javax.swing.JPanel;
+
+ at Deprecated
+public class DisplayJAI extends JPanel {
+
+    /** image to display */
+    protected RenderedImage source = null;
+
+    /** image origin relative to panel origin */
+    protected int originX = 0;
+    protected int originY = 0;
+
+
+    /** default constructor */
+    public DisplayJAI() {
+        super();
+        setLayout(null);
+    }
+
+    /** constructor with given image */
+    public DisplayJAI(RenderedImage image) {
+        super();
+        setLayout(null);
+        source = image;
+        setPreferredSize(new Dimension(source.getWidth(),
+                                       source.getHeight()));
+    }
+
+    /** move image within it's container */
+    public void setOrigin(int x, int y) {
+        originX = x;
+        originY = y;
+        repaint();
+    }
+
+    /** get the image origin */
+    public Point getOrigin() {
+        return new Point(originX, originY);
+    }
+
+    /** use to display a new image */
+    public void setImage(RenderedImage im) {
+        source = im;
+        repaint();
+    }
+
+    /** @return the Image */
+    public RenderedImage getImage() {
+        return source;
+    }
+
+    /** paint routine */
+    public synchronized void paintComponent(Graphics g) {
+
+        Graphics2D g2d = (Graphics2D)g;
+
+        // empty component (no image)
+        if ( source == null ) {
+            g2d.setColor(getBackground());
+            g2d.fillRect(0, 0, getWidth(), getHeight());
+            return;
+        }
+
+        // account for borders
+        Insets insets = getInsets();
+        int tx = insets.left + originX;
+        int ty = insets.top  + originY;
+
+        // clear damaged component area
+        Rectangle clipBounds = g2d.getClipBounds();
+        g2d.setColor(getBackground());
+        g2d.fillRect(clipBounds.x,
+                     clipBounds.y,
+                     clipBounds.width,
+                     clipBounds.height);
+
+        /**
+            Translation moves the entire image within the container
+        */
+        g2d.drawRenderedImage(source,
+                              AffineTransform.getTranslateInstance(tx, ty));
+    }
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/OSXAdapter.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/OSXAdapter.java
new file mode 100755
index 0000000..3cf06cc
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/OSXAdapter.java
@@ -0,0 +1,224 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+
+File: OSXAdapter.java
+
+Abstract: Hooks existing preferences/about/quit functionality from an
+    existing Java app into handlers for the Mac OS X application menu.
+    Uses a Proxy object to dynamically implement the 
+    com.apple.eawt.ApplicationListener interface and register it with the
+    com.apple.eawt.Application object.  This allows the complete project
+    to be both built and run on any platform without any stubs or 
+    placeholders. Useful for developers looking to implement Mac OS X 
+    features while supporting multiple platforms with minimal impact.
+			
+Version: 2.0
+
+Disclaimer: IMPORTANT:  This Apple software is supplied to you by 
+Apple Inc. ("Apple") in consideration of your agreement to the
+following terms, and your use, installation, modification or
+redistribution of this Apple software constitutes acceptance of these
+terms.  If you do not agree with these terms, please do not use,
+install, modify or redistribute this Apple software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, Apple grants you a personal, non-exclusive
+license, under Apple's copyrights in this original Apple software (the
+"Apple Software"), to use, reproduce, modify and redistribute the Apple
+Software, with or without modifications, in source and/or binary forms;
+provided that if you redistribute the Apple Software in its entirety and
+without modifications, you must retain this notice and the following
+text and disclaimers in all such redistributions of the Apple Software. 
+Neither the name, trademarks, service marks or logos of Apple Inc. 
+may be used to endorse or promote products derived from the Apple
+Software without specific prior written permission from Apple.  Except
+as expressly stated in this notice, no other rights or licenses, express
+or implied, are granted by Apple herein, including but not limited to
+any patent rights that may be infringed by your derivative works or by
+other works in which the Apple Software may be incorporated.
+
+The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
+MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
+OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
+
+IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
+MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
+STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+Copyright � 2003-2007 Apple, Inc., All Rights Reserved
+
+*/
+
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.lang.reflect.*;
+import java.util.HashMap;
+
+ at Deprecated
+public class OSXAdapter implements InvocationHandler {
+
+    protected Object targetObject;
+    protected Method targetMethod;
+    protected String proxySignature;
+    
+    static Object macOSXApplication;
+
+    // Pass this method an Object and Method equipped to perform application shutdown logic
+    // The method passed should return a boolean stating whether or not the quit should occur
+    public static void setQuitHandler(Object target, Method quitHandler) {
+        setHandler(new OSXAdapter("handleQuit", target, quitHandler));
+    }
+    
+    // Pass this method an Object and Method equipped to display application info
+    // They will be called when the About menu item is selected from the application menu
+    public static void setAboutHandler(Object target, Method aboutHandler) {
+        boolean enableAboutMenu = (target != null && aboutHandler != null);
+        if (enableAboutMenu) {
+            setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
+        }
+        // If we're setting a handler, enable the About menu item by calling
+        // com.apple.eawt.Application reflectively
+        try {
+            Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class });
+            enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) });
+        } catch (Exception ex) {
+            System.err.println("OSXAdapter could not access the About Menu");
+            ex.printStackTrace();
+        }
+    }
+    
+    // Pass this method an Object and a Method equipped to display application options
+    // They will be called when the Preferences menu item is selected from the application menu
+    public static void setPreferencesHandler(Object target, Method prefsHandler) {
+        boolean enablePrefsMenu = (target != null && prefsHandler != null);
+        if (enablePrefsMenu) {
+            setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
+        }
+        // If we're setting a handler, enable the Preferences menu item by calling
+        // com.apple.eawt.Application reflectively
+        try {
+            Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
+            enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) });
+        } catch (Exception ex) {
+            System.err.println("OSXAdapter could not access the About Menu");
+            ex.printStackTrace();
+        }
+    }
+    
+    // Pass this method an Object and a Method equipped to handle document events from the Finder
+    // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the 
+    // application bundle's Info.plist
+    public static void setFileHandler(Object target, Method fileHandler) {
+        setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
+            // Override OSXAdapter.callTarget to send information on the
+            // file to be opened
+            public boolean callTarget(Object appleEvent) {
+                if (appleEvent != null) {
+                    try {
+                        Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null);
+                        String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null);
+                        this.targetMethod.invoke(this.targetObject, new Object[] { filename });
+                    } catch (Exception ex) {
+                        
+                    }
+                }
+                return true;
+            }
+        });
+    }
+    
+    // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
+    public static void setHandler(OSXAdapter adapter) {
+        try {
+            Class applicationClass = Class.forName("com.apple.eawt.Application");
+            if (macOSXApplication == null) {
+                macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null);
+            }
+            Class applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
+            Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass });
+            // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
+            Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter);
+            addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy });
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println("This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (" + cnfe + ")");
+        } catch (Exception ex) {  // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
+            System.err.println("Mac OS X Adapter could not talk to EAWT:");
+            ex.printStackTrace();
+        }
+    }
+
+    // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
+    // the Object that will ultimately perform the task, and the Method to be called on that Object
+    protected OSXAdapter(String proxySignature, Object target, Method handler) {
+        this.proxySignature = proxySignature;
+        this.targetObject = target;
+        this.targetMethod = handler;
+    }
+    
+    // Override this method to perform any operations on the event 
+    // that comes with the various callbacks
+    // See setFileHandler above for an example
+    public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
+        Object result = targetMethod.invoke(targetObject, (Object[])null);
+        if (result == null) {
+            return true;
+        }
+        return Boolean.valueOf(result.toString()).booleanValue();
+    }
+    
+    // InvocationHandler implementation
+    // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
+    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
+        if (isCorrectMethod(method, args)) {
+            boolean handled = callTarget(args[0]);
+            setApplicationEventHandled(args[0], handled);
+        }
+        // All of the ApplicationListener methods are void; return null regardless of what happens
+        return null;
+    }
+    
+    // Compare the method that was called to the intended method when the OSXAdapter instance was created
+    // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
+    protected boolean isCorrectMethod(Method method, Object[] args) {
+        return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
+    }
+    
+    // It is important to mark the ApplicationEvent as handled and cancel the default behavior
+    // This method checks for a boolean result from the proxy method and sets the event accordingly
+    protected void setApplicationEventHandled(Object event, boolean handled) {
+        if (event != null) {
+            try {
+                Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class });
+                // If the target method returns a boolean, use that as a hint
+                setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
+            } catch (Exception ex) {
+                System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
+                ex.printStackTrace();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelBuiltFromXML.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelBuiltFromXML.java
new file mode 100755
index 0000000..c4555e2
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelBuiltFromXML.java
@@ -0,0 +1,176 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.awt.event.ActionEvent;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public class PanelBuiltFromXML extends JPanel
+{
+    private List<ComponentFromXML> components;
+
+    public PanelBuiltFromXML(byte[] xml)
+    {
+        SAXReader saxReader = new SAXReader();
+
+        Document document = null;
+        try
+        {
+            document = saxReader.read(new ByteArrayInputStream(xml));
+        } catch (DocumentException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        Element root = document.getRootElement();
+        if (root.getName().compareTo("jpanel") != 0)
+        {
+            return;
+        }
+        List<Element> elements = root.elements("component");
+        this.components = new ArrayList<ComponentFromXML>();
+
+        for (Element e : elements)
+        {
+            ComponentFromXML newComponent = new ComponentFromXML(e);
+            if (newComponent.isValidComponent())
+            {
+                this.components.add(newComponent);
+            }
+
+        }
+    }
+
+    private class ComponentFromXML extends JComponent
+    {
+
+        private String name;
+        private JComponent component;
+        private boolean valid = false;
+
+        public ComponentFromXML(Element element)
+        {
+            Element tmp = element.element("name");
+            if (tmp.getText() == null)
+            {
+                return;
+            }
+            this.name = tmp.getText();
+
+            tmp = element.element("type");
+            if (tmp.getText() == null)
+            {
+                return;
+            }
+
+            if (tmp.getText().compareTo("Integer") == 0)
+            {
+                int minimum = Integer.MIN_VALUE;
+                int maximum = Integer.MAX_VALUE;
+                tmp = element.element("min");
+                if (tmp.getText() != null)
+                {
+                    minimum = Integer.parseInt(tmp.getText());
+                }
+                tmp = element.element("max");
+                if (tmp.getText() != null)
+                {
+                    maximum = Integer.parseInt(tmp.getText());
+                }
+
+                JTextField newcomponent = new JTextField();
+
+                newcomponent.addActionListener(new IntegerListener(minimum, maximum, newcomponent));
+
+                this.component = newcomponent;
+            }
+            if (tmp.getText().compareTo("Enum") == 0)
+            {
+                List<Element> tmpelems = tmp.elements("constant");
+                if ((tmpelems == null) || tmpelems.isEmpty())
+                {
+                    return;
+                }
+                String strings[] = new String[tmpelems.size()];
+                int i = 0;
+                for (Element el : tmpelems)
+                {
+                    strings[i] = el.getText();
+                    i++;
+                }
+            }
+
+            this.valid = true;
+        }
+
+        public boolean isValidComponent()
+        {
+            return this.valid;
+        }
+    }
+
+    private class IntegerListener implements java.awt.event.ActionListener
+    {
+
+        private int minimum = Integer.MIN_VALUE;
+        private int maximum = Integer.MAX_VALUE;
+        private JTextField component;
+
+        public IntegerListener(int minimum, int maximum, JTextField component)
+        {
+            if (minimum < maximum)
+            {
+                this.minimum = minimum;
+                this.maximum = maximum;
+            }
+            this.component = component;
+        }
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+            String text = this.component.getText();
+            int i = Integer.parseInt(text);
+
+            if (i < this.minimum)
+            {
+                this.component.setText(Integer.toString(this.minimum));
+            }
+            if (i > this.maximum)
+            {
+                this.component.setText(Integer.toString(this.maximum));
+            }
+            this.component.setText(Integer.toString(i));
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelPluginsController.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelPluginsController.java
new file mode 100755
index 0000000..46a0869
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/PanelPluginsController.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.io.File;
+import java.util.Collection;
+
+import net.xeoh.plugins.base.PluginManager;
+import net.xeoh.plugins.base.impl.PluginManagerFactory;
+import net.xeoh.plugins.base.util.PluginManagerUtil;
+import pt.ua.dicoogle.sdk.Utils.PluginPanel;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public class PanelPluginsController
+{
+    private Collection<PluginPanel> panels;
+    private static PanelPluginsController instance = null;
+
+    private PanelPluginsController()
+    {
+        PluginManager pm = PluginManagerFactory.createPluginManager();
+        pm.addPluginsFrom(new File("pluginClasses/").toURI());
+        PluginManagerUtil pmu = new PluginManagerUtil(pm);
+        this.panels = pmu.getPlugins(PluginPanel.class);
+    }
+
+    public static synchronized PanelPluginsController getInstance()
+    {
+        if(instance == null)
+        {
+            instance = new PanelPluginsController();
+        }
+        return instance;
+    }
+
+    public Collection<PluginPanel> getPanels()
+    {
+        return this.panels;
+    }
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/Result2Tree.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/Result2Tree.java
new file mode 100755
index 0000000..ccdc7bd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/Result2Tree.java
@@ -0,0 +1,868 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.awt.FlowLayout;
+import java.awt.image.RenderedImage;
+import java.net.URI;
+import java.rmi.NoSuchObjectException;
+import java.rmi.RemoteException;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.*;
+import org.slf4j.LoggerFactory;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import pt.ua.dicoogle.core.QueryHistorySupport;
+import pt.ua.dicoogle.rGUI.MultihomeRMIClientSocketFactory;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.rGUI.client.signals.SearchSignal;
+import pt.ua.dicoogle.rGUI.client.windows.MainWindow;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ISearchSignal;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public class Result2Tree extends Observable
+{
+    private static Result2Tree instance;
+    private static DefaultMutableTreeNode top = new DefaultMutableTreeNode("Search Results");
+    private HashMap<String, SearchResult> pendingP2PThumbnails;
+    private Set<String> patients = new HashSet<>();
+    private List<SearchResult> resultsList;
+    private long time;
+    private ISearch searchRef;
+    private ISearchSignal searchSignal;
+    /* Counter the DICOM (DIM) found */
+    private int counterPatiends = 0;
+    private int counterImages = 0;
+    private javax.swing.JPanel jPanelThumbnail;
+    private boolean agressive = false;
+    
+    private int MAX_DRAW = 20000;
+    
+    
+
+    public static synchronized Result2Tree getInstance()
+    {
+        if (instance == null)
+        {
+            instance = new Result2Tree();
+        }
+        return instance;
+    }
+
+    private Result2Tree()
+    {
+        try
+        {
+            this.resultsList = new ArrayList();
+            pendingP2PThumbnails = new HashMap<String, SearchResult>();
+
+            searchSignal = new SearchSignal(this);
+            ISearchSignal searchSignalStub = (ISearchSignal) UnicastRemoteObject.exportObject(searchSignal, 0, new MultihomeRMIClientSocketFactory(), RMISocketFactory.getDefaultSocketFactory());
+
+            searchRef = UserRefs.getInstance().getSearch();
+
+            //System.out.println("1.4.3.chegou aqui");
+            searchRef.RegisterSignalBack(searchSignalStub);
+            //System.out.println("1.4.4.chegou aqui");
+
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    
+    public void pruneQuery(String id) 
+    {
+        try {
+            searchRef.pruneQuery(id);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+    
+    public void search(String query, boolean keywords, HashMap<String, Boolean> range)
+    {
+        //
+        this.deleteObservers();
+        DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+        model.setRoot(new DefaultMutableTreeNode("Search Results"));
+        MainWindow.getInstance().getjLabelResults().setText("Searching...");
+        MainWindow.getInstance().getjLabelTime().setText("");
+        try
+        {
+            this.time = System.nanoTime();
+            this.resetCounters();
+            this.resultsList.clear();
+
+            searchRef.Search(query, keywords, range);
+
+            if (!query.equals(""))
+            {
+                QueryHistorySupport.getInstance().addQuery(query, keywords);
+            }
+
+
+            showImage("Image Thumbnail", null, jPanelThumbnail);
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void searchToExport(String query, boolean keywords, HashMap<String, Boolean> range, ArrayList<String> extraFields, Observer obs)
+    {
+        try
+        {
+            this.deleteObservers(); // delete all observers from the past
+            this.addObserver(obs);
+
+            searchRef.SearchToExport(query, keywords, range, extraFields, obs);
+
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Search only for onde File to get the Thumbnail
+     *
+     * @param FileName
+     * @param FileHash
+     * @return
+     */
+    public SearchResult searchThumbnail(URI FileName, String FileHash)
+    {
+        try
+        {
+            return searchRef.getThumbnail(FileName, FileHash);
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+
+        return null;
+    }
+
+    
+    public void finishSearch()
+    {
+        MainWindow.getInstance().finishQuery();
+    }
+    
+    
+    /**
+     * Search only for one File to get the Thumbnail in P2P network
+     *
+     * @param result
+     */
+    public void searchP2PThumbnail(SearchResult result)
+    {
+        try
+        {
+            searchRef.getP2PThumbnail(result.getURI(), (String)result.getExtraData().get("filehash"), result.getURI().toString());
+
+            pendingP2PThumbnails.put((String)result.getExtraData().get("filehash"), result);
+
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    // <editor-fold defaultstate="collapsed" desc="showImage">
+    public static void showImage(String title, RenderedImage image, JPanel panel)
+    {
+        if (panel == null)
+        {
+
+            /** It can be used to show image in external window*/
+            JFrame f = new JFrame(title);
+            if (image != null)
+            {
+                f.getContentPane().add(new DisplayJAI(image));
+            }
+            f.pack();
+            //f.setVisible(true);
+            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        } else
+        {
+            panel.removeAll();
+            panel.setLayout(new FlowLayout());
+
+            // Yet another bugfix
+            // If the indexed image does not have a thumbnail, it leads to a Null Pointer Exception
+            if (image != null)
+            {
+                panel.add(new DisplayJAI(image));
+            }
+
+            panel.validate();
+            panel.setVisible(true);
+        }
+    }// </editor-fold>
+
+    public DefaultMutableTreeNode convertQueryResult2Tree(List queryResultL)
+    {
+        LoggerFactory.getLogger(Result2Tree.class).trace("Chegou a convertQueryResult2Tree com :" + queryResultL.size());
+        top.removeAllChildren();
+        //this.resultsList = queryResultL;
+
+        if (queryResultL != null)
+        {
+            HashMap<String, HashMap> names = nameToTree();
+            fillTree(names);
+            
+        }
+
+        return top;
+    }
+
+    /**
+     * Convert a String indexed (given in UTF) to ASCII normal mode
+     * @param utfString utf string (2chars per bit) with terminal char
+     * @return n ascii string (1 char per bit) without terminal char
+     */
+    private String asciiMode(String utfString)
+    {
+        /*String n = null;
+        try
+        {
+            n = new String(utfString.getBytes("US-ASCII"));
+        } catch (UnsupportedEncodingException ex)
+        {
+            ex.printStackTrace();
+            return null;
+        }*/
+        return utfString.trim();
+        //return n.trim();
+
+    }
+
+    /**
+     * This function is necessary to grep the resultList
+     *
+     * @param patientName - returns only the search results that have the same PatientName
+     * @return
+     */
+    private ArrayList<SearchResult> grepByPatientName(String patientName)
+    {
+        ArrayList<SearchResult> tmpList = new ArrayList<SearchResult>();
+        HashMap extra;
+
+        for (SearchResult tmp : resultsList)
+        {
+            String _n = null;
+
+            if (tmp instanceof SearchResult)
+            {
+                extra = tmp.getExtraData();
+                _n = (String) extra.get("PatientName");
+            } else if (tmp instanceof SearchResult)
+            {
+                // TODO...
+            }
+
+            if (_n != null && asciiMode(_n).equals(patientName))
+            {
+                tmpList.add(tmp);
+            }
+        }
+
+        return tmpList;
+    }
+
+    private ArrayList<SearchResult> grepByStudyDate(String patientName, String studyDate)
+    {
+
+        ArrayList<SearchResult> tmpList = new ArrayList<SearchResult>();
+        HashMap extra;
+
+        for (SearchResult tmp : resultsList)
+        {
+            String _patientName = null;
+            String _studyDate = null;
+
+            extra = tmp.getExtraData();
+            _patientName = (String) extra.get("PatientName");
+            _studyDate = (String) extra.get("StudyDate");
+
+            if (_patientName != null && asciiMode(_patientName).equals(patientName) && _studyDate.equals(studyDate))
+            {
+                tmpList.add(tmp);
+            }
+        }
+
+        return tmpList;
+
+    }
+
+    private ArrayList<SearchResult> grepByModality(String patientName, String studyDate, String modality)
+    {
+        ArrayList<SearchResult> tmpList = new ArrayList<SearchResult>();
+        HashMap extra;
+
+        for (SearchResult tmp : resultsList)
+        {
+            String _patientName = null;
+            String _studyDate = null;
+            String _modality = null;
+
+
+            extra = tmp.getExtraData();
+            _patientName = (String) extra.get("PatientName");
+            _studyDate = (String) extra.get("StudyDate");
+            _modality = (String) extra.get("Modality");
+
+            if (_patientName != null && asciiMode(_patientName).equals(patientName) && _studyDate.equals(studyDate)
+                    && _modality.equals(modality))
+            {
+                tmpList.add(tmp);
+            }
+        }
+        return tmpList;
+
+    }
+
+    public void completeTree(javax.swing.event.TreeExpansionEvent evt)
+    {
+        if (agressive)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).trace("completeTree, Aggressive mode");
+            return;
+        }
+
+        //long tBegin = System.nanoTime();
+
+        int level = evt.getPath().getPathCount();
+        LoggerFactory.getLogger(Result2Tree.class).trace("level calculated {}", level);
+        if (level == 2)
+        {
+            // Study
+            //DebugManager.getInstance().debug("Study");
+            //System.out.println("PatientName:" + evt.getPath().getPathComponent(1));
+            LoggerFactory.getLogger(Result2Tree.class).trace("level 2");
+            DefaultMutableTreeNode patient_name = (DefaultMutableTreeNode) evt.getPath().getPathComponent(1);
+
+            if (patient_name.getFirstChild().isLeaf())
+            {
+                LoggerFactory.getLogger(Result2Tree.class).trace("PatientName: {}", patient_name );
+                completeByName(patient_name);
+            }
+
+
+            //System.out.println("Chegou ao fim");
+        } else if (level == 3)
+        {
+            // Serie
+            //DebugManager.getInstance().debug("Serie");
+            //System.out.println("Study Date:" + evt.getPath().getPathComponent(2));
+            LoggerFactory.getLogger(Result2Tree.class).trace("completeTree - level 3");
+            DefaultMutableTreeNode study_date = (DefaultMutableTreeNode) evt.getPath().getPathComponent(2);
+
+            if (study_date.getFirstChild().isLeaf())
+            {
+                completeByStudyDate(study_date);
+            }
+        } else if (level == 4)
+        {
+            // Image
+            //DebugManager.getInstance().debug("Image");
+            //System.out.println("Modality:" + evt.getPath().getPathComponent(3));
+            LoggerFactory.getLogger(Result2Tree.class).trace("completeTree - level 4");
+            DefaultMutableTreeNode modality = (DefaultMutableTreeNode) evt.getPath().getPathComponent(3);
+
+            if (modality.getFirstChild().isLeaf())
+            {
+                completeByModality(modality);
+            }
+        }
+
+        //long tEnd = System.nanoTime();
+
+        //System.out.println("TIME COMPLETE TREE");
+        //System.out.println(Integer.toString((int) ( ( tEnd - tBegin ) / 1000000L )));
+    }
+
+    private void completeByName(DefaultMutableTreeNode patient_name)
+    {
+        ArrayList<SearchResult> result = grepByPatientName(patient_name.toString());
+
+        patient_name.removeAllChildren();
+
+        DefaultMutableTreeNode date;
+        HashMap extra;
+        HashSet<String> studyDates = new HashSet<String>(); // to elimitate repetition
+
+        LoggerFactory.getLogger(Result2Tree.class).trace("result size" + result.size());
+        for (SearchResult temp : result)
+        {
+            extra = temp.getExtraData();
+            studyDates.add((String) extra.get("StudyDate"));
+        }
+        Iterator<String> it = studyDates.iterator();
+
+        while (it.hasNext())
+        {
+            date = new DefaultMutableTreeNode(it.next());
+            date.add(new DefaultMutableTreeNode("Loading.."));
+
+            patient_name.add(date);
+        }
+
+        DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+        model.reload(patient_name);
+    }
+
+    private void completeByStudyDate(DefaultMutableTreeNode study_date)
+    {
+        DefaultMutableTreeNode patient_name = (DefaultMutableTreeNode) study_date.getParent();
+
+        ArrayList<SearchResult> result = grepByStudyDate(patient_name.toString(), study_date.toString());
+
+        study_date.removeAllChildren();
+
+        DefaultMutableTreeNode modality;
+        HashMap extra;
+        HashSet<String> modalities = new HashSet<String>(); // to elimitate repetition
+
+        for (SearchResult temp : result)
+        {
+            extra = temp.getExtraData();
+            modalities.add((String) extra.get("Modality"));
+        }
+        Iterator<String> it = modalities.iterator();
+
+        while (it.hasNext())
+        {
+            modality = new DefaultMutableTreeNode(it.next());
+            modality.add(new DefaultMutableTreeNode("Loading.."));
+
+            study_date.add(modality);
+        }
+
+        DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+        model.reload(study_date);
+    }
+
+    private void completeByModality(DefaultMutableTreeNode modality)
+    {
+        DefaultMutableTreeNode study_date = (DefaultMutableTreeNode) modality.getParent();
+        DefaultMutableTreeNode patient_name = (DefaultMutableTreeNode) study_date.getParent();
+
+        ArrayList<SearchResult> result = grepByModality(patient_name.toString(), study_date.toString(), modality.toString());
+
+        modality.removeAllChildren();
+
+        DefaultMutableTreeNode image;
+        Hashtable extra;
+        Hashtable<String, ArrayList<SearchResult>> files = new Hashtable<String, ArrayList<SearchResult>>();
+
+        // to elimitate possible repetition from p2p
+        for (SearchResult temp : result)
+        {
+            ArrayList<SearchResult> list = files.get(temp.getURI() + " : " + temp.getExtraData().get("filehash"));
+
+            if (list == null)
+            {
+                list = new ArrayList<SearchResult>();
+                files.put(temp.getURI() + " : " + temp.getExtraData().get("filehash"), list);
+            }
+
+            list.add(temp);
+        }
+
+        Iterator<String> it = files.keySet().iterator();
+
+        while (it.hasNext())
+        {
+            String fileDesc = it.next();
+
+            ArrayList<SearchResult> sr = files.get(fileDesc);
+
+            DefaultMutableTreeNode DescFile = new DefaultMutableTreeNode(fileDesc);
+
+            Iterator<SearchResult> iter = sr.iterator();
+
+            while (iter.hasNext())
+            {
+                DescFile.add(new DefaultMutableTreeNode(iter.next()));
+            }
+
+            modality.add(DescFile);
+        }
+
+
+        DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+        model.reload(modality);
+    }
+
+    
+    private HashMap<String, HashMap> nameToTree()
+    {
+        /* Hashtable to support */
+        HashMap<String, HashMap> tree = new HashMap<String, HashMap>();
+        //resetCounters();
+        
+        for (SearchResult tmp : resultsList)
+        {
+            String _n = (String)tmp.getExtraData().get("PatientName");
+
+            if (_n != null)
+            {
+                String n = asciiMode(_n);
+
+                HashMap<String, HashMap> studies = tree.get(n);
+                
+                if( !this.patients.contains(n))
+                
+                {
+                    this.patients.add(n);
+                    counterPatiends++;
+                }
+                if (studies == null)
+                {
+                    
+
+                    if (agressive)
+                    {
+                        studies = new HashMap<String, HashMap>();
+                        tree.put(n, studies);
+
+                        dateToTree(studies, tmp);
+                    } else
+                    {
+                        studies = new HashMap<String, HashMap>();
+                        studies.put("Loading", new HashMap());
+
+                        tree.put(n, studies);
+                    }
+                } else if (agressive)
+                {
+                    dateToTree(studies, tmp);
+                }
+
+            } else
+            {
+                System.out.println("Problem \"PatientName == null\"");
+                //the file indexed is not DICOM or there is a problem in the result
+            }
+
+        }
+        return tree;
+    }
+
+    private void dateToTree(HashMap<String, HashMap> studies, SearchResult result)
+    {
+
+        String date = (String) result.getExtraData().get("StudyDate");
+        if (date.equals(""))
+        {
+            date = "00000000 ";
+        }
+
+        HashMap<String, HashMap> modalities = studies.get(date);
+
+        if (modalities == null)
+        {
+            modalities = new HashMap<String, HashMap>();
+            studies.put(date, modalities);
+        }
+
+        modalityToTree(modalities, result);
+    }
+
+    private void modalityToTree(HashMap<String, HashMap> modalities, SearchResult result)
+    {
+        String m = (String)result.getExtraData().get("Modality");
+
+        HashMap<String, ArrayList<SearchResult>> images = modalities.get(m);
+
+        if (images == null)
+        {
+            images = new HashMap<String, ArrayList<SearchResult>>();
+            modalities.put(m, images);
+        }
+
+        resToTree(images, result);
+    }
+
+    private void resToTree(HashMap<String, ArrayList<SearchResult>> images, SearchResult result)
+    {
+        String fileDesc = result.getURI() + " : " + result.getExtraData().get("filehash");
+
+        ArrayList<SearchResult> file = images.get(fileDesc);
+
+        if (file == null)
+        {
+            file = new ArrayList<>();
+
+            images.put(fileDesc, file);
+        }
+
+        addressToTree(file, result);
+    }
+
+    private void addressToTree(ArrayList<SearchResult> fileList, SearchResult result)
+    {
+        fileList.add(result);
+    }
+
+    /**
+     * Fill the tree
+     *
+     * @param tree - HashTable with the tree
+     */
+    private void fillTree(HashMap<String, HashMap> tree)
+    {
+        Iterator<String> en_tree = tree.keySet().iterator();
+
+        while (en_tree.hasNext())   //Patient Names
+        {
+            String name = en_tree.next();
+
+            HashMap<String, HashMap> t_date = tree.get(name);
+
+            DefaultMutableTreeNode patient_name = new DefaultMutableTreeNode(name);
+
+            Iterator<String> en_date = t_date.keySet().iterator();
+
+            while (en_date.hasNext())   //Study Dates
+            {
+                String dt = en_date.next();
+
+                HashMap<String, HashMap> t_mod = (HashMap) t_date.get(dt);
+
+                DefaultMutableTreeNode date = new DefaultMutableTreeNode(dt);
+
+                Iterator<String> en_mod = t_mod.keySet().iterator();
+
+                while (en_mod.hasNext()) //Modalities
+                {
+                    String md = en_mod.next();
+
+                    HashMap<String, ArrayList> t_name = t_mod.get(md);
+
+                    DefaultMutableTreeNode modality = new DefaultMutableTreeNode(md);
+
+                    Iterator<String> en_fname = t_name.keySet().iterator();
+
+                    while (en_fname.hasNext()) //FileDescription
+                    {
+
+                        String fname = en_fname.next();
+                        ArrayList<SearchResult> res = t_name.get(fname);
+                        DefaultMutableTreeNode filename = new DefaultMutableTreeNode(fname);
+
+                        for (SearchResult tmp : res) //SearchResult
+                        {
+                            DefaultMutableTreeNode details = new DefaultMutableTreeNode(tmp);
+                            filename.add(details);
+                        }
+
+                        modality.add(filename);
+                    }
+                    date.add(modality);
+                }
+                patient_name.add(date);
+            }
+            top.add(patient_name);
+        }
+
+        if (this.resultsList.isEmpty())
+        {
+            MainWindow.getInstance().getjLabelResults().setText("No matches found.");
+        } else
+        {
+            MainWindow.getInstance().getjLabelResults().setText("<HTML>" + counterImages + " matches found <BR>"
+                    + "Patients:" + counterPatiends + "<BR>"
+                    //  + "Studies:"+  counterStudies +"<BR>"
+                    //  + "Series:"+ counterSeries+"<BR>" +
+                    + "</HTML>");
+        }
+
+        long timeEnd = System.nanoTime();
+        MainWindow.getInstance().getjLabelTime().setText(Integer.toString((int) ((timeEnd - time) / 1000000L)));
+    }
+
+    private void resetCounters()
+    {
+        
+        patients = new HashSet<String>();
+        counterPatiends = 0;
+        counterImages = 0;
+    }
+
+    public void getSearchTime()
+    {
+        try
+        {
+            long serverSearchTime = searchRef.getSearchTime();
+
+            MainWindow.getInstance().getjLabelTime().setText(String.valueOf(serverSearchTime));
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * get the Local Search Results from the GUI Server
+     */
+    public void getLocalSearchResults()
+    {
+        try
+        {
+            resultsList = searchRef.getSearchResults();
+
+            DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+            
+            model.setRoot(convertQueryResult2Tree(resultsList));
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    /**
+     * get the P2P Search Results from the GUI Server
+     */
+    public void getP2PSearchResults()
+    {
+
+        LoggerFactory.getLogger(Result2Tree.class).trace("getP2PSearchResults");
+        
+        try
+        {
+            this.resultsList = new ArrayList();
+            List<SearchResult> temp = searchRef.getP2PSearchResults();
+            counterImages += temp.size();
+            if (temp != null)
+            {
+                this.resultsList.addAll(temp);
+                //counterImages += resultsList.size();
+            }
+            
+            
+            DefaultTreeModel model = (DefaultTreeModel) MainWindow.getInstance().getjTreeResults().getModel();
+            
+            DefaultMutableTreeNode root = convertQueryResult2Tree(temp);
+            if (temp.size()<=MAX_DRAW)
+            {
+                model.setRoot(root);
+                MainWindow.getInstance().repaint();
+                
+            }
+            
+            LoggerFactory.getLogger(Result2Tree.class.getName()).trace("getP2PSearchResults, size of resultList {}", resultsList.size());
+            
+            LoggerFactory.getLogger(Result2Tree.class.getName()).trace("getP2PSearchResults, size of tmpSize {}", temp.size());
+            
+
+            
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    /**
+     * get the Search Results with the selected extraFields to export data to a file
+     */
+    public void getExportSearchResults()
+    {
+        try
+        {
+            List<SearchResult> temp = searchRef.getExportSearchResults();
+
+            if (temp != null)
+            {
+                setChanged();
+                notifyObservers(temp);
+                
+            }
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void getPendingP2PThumbnails()
+    {
+        try
+        {
+            ArrayList<SearchResult> thumbnails = searchRef.getPendingP2PThumnails();
+
+            SearchResult res;
+            String thumb;
+
+            for (SearchResult temp : thumbnails)
+            {
+                res = pendingP2PThumbnails.remove(temp.get("filehash"));
+                thumb = (String) temp.get("Thumbnail");
+
+                if (res != null && thumb != null)
+                {
+                    res.put("Thumbnail", thumb);
+                    MainWindow.getInstance().updateP2PThumbnail(res);
+                }
+            }
+
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Unexport the remote object SearchSignal
+     */
+    public void unexportSearchSignal()
+    {
+        try
+        {
+            if (searchSignal != null)
+            {
+                UnicastRemoteObject.unexportObject(searchSignal, true);
+            }
+        } catch (NoSuchObjectException ex)
+        {
+            LoggerFactory.getLogger(Result2Tree.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public DefaultMutableTreeNode getTop()
+    {
+        return top;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/ServerMessagesManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/ServerMessagesManager.java
new file mode 100755
index 0000000..f9988a1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/ServerMessagesManager.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import java.rmi.RemoteException;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.MultihomeRMIClientSocketFactory;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.client.signals.PendingMessagesSignal;
+import pt.ua.dicoogle.rGUI.client.windows.FileAlreadyIndexed;
+import pt.ua.dicoogle.rGUI.interfaces.signals.IPendingMessagesSignal;
+
+/**
+ * This class deals with the server messages to the administrator
+ * For now it deals only with file Already Indexed message
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class ServerMessagesManager {
+
+    private static PendingMessagesSignal pendingMessagesSignal;
+
+    private static ServerMessagesManager instance;
+
+    public static synchronized ServerMessagesManager getInstance() {
+        if (instance == null) {
+            instance = new ServerMessagesManager();
+        }
+
+        return instance;
+    }
+
+    private ServerMessagesManager(){
+        try {
+
+            pendingMessagesSignal = new PendingMessagesSignal(this);
+            IPendingMessagesSignal pendingMessagesSignalStub = (IPendingMessagesSignal) UnicastRemoteObject.exportObject(pendingMessagesSignal, 0, new MultihomeRMIClientSocketFactory(), RMISocketFactory.getDefaultSocketFactory());
+
+            AdminRefs.getInstance().getPendingMessages().RegisterSignalBack(pendingMessagesSignalStub);
+            
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ServerMessagesManager.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void newFileAlreadyIndexedMessage(){
+        FileAlreadyIndexed.getInstance().getList();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/TrayIconCreator.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/TrayIconCreator.java
new file mode 100755
index 0000000..755a3b1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UIHelper/TrayIconCreator.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.UIHelper;
+
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.client.windows.MainWindow;
+
+import java.awt.*;
+import java.net.URL;
+import java.util.concurrent.Semaphore;
+
+/**
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class TrayIconCreator {
+
+    private static TrayIconCreator instance = null;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    private TrayIcon trayIcon;
+
+    public static synchronized TrayIconCreator getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new TrayIconCreator();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UserRefs.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UserRefs.java
new file mode 100755
index 0000000..f5d3a02
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/UserRefs.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client;
+
+import java.rmi.RemoteException;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDicomSend;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class UserRefs {
+
+    private ISearch search;
+    private IDicomSend dicomSend;
+
+    private IUser user;
+
+    private static UserRefs instance;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized UserRefs getUserRefs(final IUser user) {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new UserRefs(user);
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(ClientCore.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    public static UserRefs getInstance() {
+        return instance;
+    }
+    
+    private UserRefs(IUser user){
+        this.user = user;
+
+        getRefs();
+    }
+
+    /**
+     * This function is responsible for obtaining references to Remote user objects
+     */
+    private void getRefs() {
+        class GetReferences  {
+
+
+            public void run() {
+                try {
+                    //System.out.println("Starting to adquire User Refs");
+
+                    search = user.getSearch();
+                    dicomSend = user.getDicomSend();
+
+                    //System.out.println("User Refs Adquired");
+                } catch (RemoteException ex) {
+                    LoggerFactory.getLogger(AdminRefs.class).error(ex.getMessage(), ex);
+
+                    //TODO: se falhar, ter?? implica????es... o programa cliente deve parar
+                }
+            }
+        }
+        GetReferences getRefs = new GetReferences();
+
+        //starts the Thread that will get the remote administrations object references
+        getRefs.run();
+
+    }
+
+    /**
+     * @return the search
+     */
+    public ISearch getSearch() {
+        return search;
+    }
+
+    /**
+     * @return the dicomSend
+     */
+    public IDicomSend getDicomSend() {
+        return dicomSend;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/LogsSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/LogsSignal.java
new file mode 100755
index 0000000..2925a6a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/LogsSignal.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.signals;
+
+import java.rmi.RemoteException;
+import pt.ua.dicoogle.rGUI.client.windows.Logs;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ILogsSignal;
+
+/**
+ * This class is responsible for handle with callbacks of Log Server
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class LogsSignal implements ILogsSignal{
+    private Logs log;
+
+    public LogsSignal(Logs log) throws NullPointerException{
+        if (log == null)
+            throw new NullPointerException("log can't be null");
+        
+        this.log = log;
+    }
+
+
+    /**
+     *
+     * @param flag
+     *              0 - DICOM Log
+     *              1 - Server Log
+     *              2 - User Sessions Log
+     * @throws RemoteException
+     */
+    @Override
+    public void sendLogSignal(int flag) throws RemoteException {
+        //System.out.println("Recebeu Flag: " + flag);
+        switch(flag){
+            case 0:
+                log.getDICOMLog();
+                break;
+            case 1:
+                log.getServerLog();
+                break;
+            case 2:
+                log.getSessionsLog();
+                break;
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/PendingMessagesSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/PendingMessagesSignal.java
new file mode 100755
index 0000000..6634308
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/PendingMessagesSignal.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.signals;
+
+import java.rmi.RemoteException;
+import pt.ua.dicoogle.rGUI.client.UIHelper.ServerMessagesManager;
+import pt.ua.dicoogle.rGUI.interfaces.signals.IPendingMessagesSignal;
+
+/**
+ * Class that implements the signal object related to the penging messages
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class PendingMessagesSignal implements IPendingMessagesSignal {
+
+    private ServerMessagesManager sMM;
+
+    public PendingMessagesSignal(ServerMessagesManager sMM){
+        if (sMM == null)
+            throw new NullPointerException("ServerMessagesManager can't be null");
+
+        this.sMM = sMM;
+    }
+
+    /**
+     *
+     * @param flag
+     *              0 - File Already Indexed
+     * @throws RemoteException
+     */
+    @Override
+    public void sendPendingMessagesSignal(int flag) throws RemoteException {
+        switch(flag){
+            case 0:
+                sMM.newFileAlreadyIndexedMessage();
+                
+        }
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/SearchSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/SearchSignal.java
new file mode 100755
index 0000000..679d33e
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/SearchSignal.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.signals;
+
+import java.rmi.RemoteException;
+import pt.ua.dicoogle.rGUI.client.UIHelper.Result2Tree;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ISearchSignal;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class SearchSignal implements ISearchSignal {
+    private Result2Tree result;
+
+    public SearchSignal(Result2Tree result) throws NullPointerException{
+        if (result == null)
+            throw new NullPointerException("main can't be null");
+
+        this.result = result;
+    }
+
+    /**
+     *
+     * @param flag
+     *              0 - new ArrayList<SearchResult> with the local results
+     *              1 - new ArrayList<SearchResultP2P> with the P2P results
+     *              2 - new SearchTime
+     *              3 - new ArrayList<SearchResultP2P> with P2P Thumbnails requested
+     *              4 - new ArrayList<SearchResult> with the results
+     *              5 - Finish search
+     * @throws RemoteException
+     */
+    @Override
+    public void sendSearchSignal(int flag) throws RemoteException {
+        switch(flag){
+            case 0:
+                result.getLocalSearchResults();
+                break;
+
+            case 1:
+                result.getP2PSearchResults();
+                break;
+
+            case 2:
+                result.getSearchTime();
+                break;
+
+            case 3:
+                result.getPendingP2PThumbnails();
+                break;
+
+            case 4:
+                result.getExportSearchResults();
+                break;
+                
+            case 5:
+                result.finishSearch();
+                break;
+     
+                
+
+        }
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/TaskListSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/TaskListSignal.java
new file mode 100755
index 0000000..4876754
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/signals/TaskListSignal.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.signals;
+
+import java.rmi.RemoteException;
+import pt.ua.dicoogle.rGUI.client.windows.TaskList;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ITaskListSignal;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public class TaskListSignal implements ITaskListSignal
+{
+    TaskList taskListWindow = null;
+
+    public TaskListSignal(TaskList tasks)
+    {
+        taskListWindow = tasks;
+    }
+
+    @Override
+    public synchronized void sendTaskSignal(int flag) throws RemoteException
+    {
+        switch(flag){
+            case 0:
+               // taskListWindow.getTaskList();
+                break;
+            
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.form
new file mode 100755
index 0000000..f64856e
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.form
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="buttonGroup1">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[446, 291]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+    <EventHandler event="componentShown" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="formComponentShown"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="41" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                  <Group type="102" alignment="1" attributes="1">
+                      <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                      <Component id="jButtonLogout" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="103" alignment="1" groupAlignment="0" attributes="0">
+                      <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                      <Component id="jScrollPane1" alignment="0" min="-2" pref="367" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace pref="38" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace pref="21" max="32767" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jScrollPane1" min="-2" pref="188" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButtonLogout" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListUsers">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JList(model)"/>
+            <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="DefaultListModel model = new DefaultListModel();"/>
+          </AuxValues>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonLogout">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Logout User"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonLogoutActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Active users in this moment:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="List Refresh Time: 10 seconds"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.java
new file mode 100755
index 0000000..a989bae
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ActiveSessions.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ActiveSessions.java
+ *
+ * Created on 26/Abr/2010, 14:56:44
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IActiveSessions;
+import pt.ua.dicoogle.server.users.UserON;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at Deprecated
+public class ActiveSessions extends javax.swing.JFrame {
+    private HashMap<Integer, UserON> usersTable;
+    private IActiveSessions activeSessions;
+
+    private int adminID = -1;
+
+    private Timer timer;
+    private static int timeoutTime = 10000;  //10 seconds
+    private TimerTask task;
+
+    private static ActiveSessions instance = null;
+
+    public static synchronized ActiveSessions getInstance() {
+        if (instance == null) {
+            instance = new ActiveSessions();
+        }
+        return instance;
+    }
+
+    /** Creates new form ActiveSessions */
+    private ActiveSessions() {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        this.setTitle("Active Users");
+        timer = new Timer();
+
+        activeSessions = AdminRefs.getInstance().getActiveSessions();
+
+        try {
+            adminID = activeSessions.getAdminID();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ActiveSessions.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    private void RefreshUsers(){
+        try {
+            usersTable = activeSessions.getUsersTable();
+
+            DefaultListModel model = (DefaultListModel) jListUsers.getModel();
+            model.clear();
+
+            Iterator<Integer> en = usersTable.keySet().iterator();
+
+            while(en.hasNext())
+                model.addElement(usersTable.get(en.next()));
+
+            jListUsers.setModel(model);
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ActiveSessions.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        buttonGroup1 = new javax.swing.ButtonGroup();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        DefaultListModel model = new DefaultListModel();
+        jListUsers = new javax.swing.JList(model);
+        jButtonLogout = new javax.swing.JButton();
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setMinimumSize(new java.awt.Dimension(446, 291));
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+        addComponentListener(new java.awt.event.ComponentAdapter() {
+            public void componentShown(java.awt.event.ComponentEvent evt) {
+                formComponentShown(evt);
+            }
+        });
+
+        jScrollPane1.setViewportView(jListUsers);
+
+        jButtonLogout.setText("Logout User");
+        jButtonLogout.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonLogoutActionPerformed(evt);
+            }
+        });
+
+        jLabel1.setText("Active users in this moment:");
+
+        jLabel2.setText("List Refresh Time: 10 seconds");
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(41, 41, 41)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
+                    .add(layout.createSequentialGroup()
+                        .add(jLabel2)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .add(jButtonLogout))
+                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                        .add(jLabel1)
+                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 367, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap(38, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                .addContainerGap(21, Short.MAX_VALUE)
+                .add(jLabel1)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 188, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jButtonLogout)
+                    .add(jLabel2))
+                .add(20, 20, 20))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonLogoutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonLogoutActionPerformed
+        try {
+            UserON user = (UserON) jListUsers.getSelectedValue();
+
+            if(user != null){
+                if(user.getUserID() != adminID){
+                    if(activeSessions.adminLogoutUser(user.getUserID()))
+                        RefreshUsers();
+                }
+                else
+                    JOptionPane.showMessageDialog(this, "You can't logout yourself.",
+                    "User Selection", JOptionPane.INFORMATION_MESSAGE);
+            }
+            else
+                JOptionPane.showMessageDialog(this, "Please select one user.",
+                "User Selection", JOptionPane.INFORMATION_MESSAGE);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ActiveSessions.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonLogoutActionPerformed
+
+    private void formComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_formComponentShown
+        task = new UsersRegfresh();
+        timer.schedule(task, 100, timeoutTime);
+    }//GEN-LAST:event_formComponentShown
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+       task.cancel();
+       timer.purge();
+    }//GEN-LAST:event_formWindowClosing
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.ButtonGroup buttonGroup1;
+    private javax.swing.JButton jButtonLogout;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JList jListUsers;
+    private javax.swing.JScrollPane jScrollPane1;
+    // End of variables declaration//GEN-END:variables
+
+    private class UsersRegfresh extends TimerTask {
+
+        @Override
+        public void run() {
+            RefreshUsers();
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.form
new file mode 100755
index 0000000..9d51815
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.form
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[370, 213]"/>
+    </Property>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="43" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jButtonCancel" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                                  <Component id="jPasswordFieldNew" alignment="1" max="32767" attributes="1"/>
+                                  <Component id="jPasswordFieldOld" alignment="1" max="32767" attributes="1"/>
+                                  <Component id="jButtonChangePass" alignment="0" max="32767" attributes="1"/>
+                                  <Component id="jPasswordFieldConfirm" alignment="0" max="32767" attributes="1"/>
+                              </Group>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
+                              <Component id="jLabelUsername" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace pref="40" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace pref="25" max="32767" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jLabelUsername" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jPasswordFieldOld" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jPasswordFieldNew" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jPasswordFieldConfirm" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="17" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButtonCancel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonChangePass" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Username:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Old Password:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="New Password:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel4">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Confirm Password:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelUsername">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Username"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JPasswordField" name="jPasswordFieldOld">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jPasswordFieldOldKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JPasswordField" name="jPasswordFieldNew">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jPasswordFieldNewKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JPasswordField" name="jPasswordFieldConfirm">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jPasswordFieldConfirmKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonCancel">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Cancel"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonCancelActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonChangePass">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Change Password"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonChangePassActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.java
new file mode 100755
index 0000000..3513098
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ChangePassword.java
@@ -0,0 +1,278 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * ChangePassword.java
+ *
+ * Created on 18/Abr/2010, 16:33:42
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.rmi.RemoteException;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.rGUI.client.ClientCore;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+import pt.ua.dicoogle.server.users.HashService;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at Deprecated
+public class ChangePassword extends javax.swing.JFrame {
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static ChangePassword instance = null;
+
+    private IUser user;
+
+    public static synchronized ChangePassword getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new ChangePassword();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(ChangePassword.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    /** Creates new form ChangePassword */
+    private ChangePassword() {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        this.setTitle("Change User Password");
+        
+        user = ClientCore.getInstance().getUser();
+        
+        try {
+            jLabelUsername.setText(user.getUsername());
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ChangePassword.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jLabel4 = new javax.swing.JLabel();
+        jLabelUsername = new javax.swing.JLabel();
+        jPasswordFieldOld = new javax.swing.JPasswordField();
+        jPasswordFieldNew = new javax.swing.JPasswordField();
+        jPasswordFieldConfirm = new javax.swing.JPasswordField();
+        jButtonCancel = new javax.swing.JButton();
+        jButtonChangePass = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setMinimumSize(new java.awt.Dimension(370, 213));
+        setPreferredSize(new java.awt.Dimension(370, 213));
+        setResizable(false);
+        setSize(new java.awt.Dimension(370, 213));
+
+        jLabel1.setText("Username:");
+
+        jLabel2.setText("Old Password:");
+
+        jLabel3.setText("New Password:");
+
+        jLabel4.setText("Confirm Password:");
+
+        jLabelUsername.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
+        jLabelUsername.setText("Username");
+
+        jPasswordFieldOld.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jPasswordFieldOldKeyPressed(evt);
+            }
+        });
+
+        jPasswordFieldNew.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jPasswordFieldNewKeyPressed(evt);
+            }
+        });
+
+        jPasswordFieldConfirm.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jPasswordFieldConfirmKeyPressed(evt);
+            }
+        });
+
+        jButtonCancel.setText("Cancel");
+        jButtonCancel.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonCancelActionPerformed(evt);
+            }
+        });
+
+        jButtonChangePass.setText("Change Password");
+        jButtonChangePass.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonChangePassActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(43, 43, 43)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jButtonCancel)
+                    .add(layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel3)
+                            .add(jLabel1)
+                            .add(jLabel2)
+                            .add(jLabel4))
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(layout.createSequentialGroup()
+                                .add(18, 18, 18)
+                                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
+                                    .add(jPasswordFieldNew)
+                                    .add(jPasswordFieldOld)
+                                    .add(org.jdesktop.layout.GroupLayout.LEADING, jButtonChangePass, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                    .add(org.jdesktop.layout.GroupLayout.LEADING, jPasswordFieldConfirm)))
+                            .add(layout.createSequentialGroup()
+                                .add(26, 26, 26)
+                                .add(jLabelUsername)))))
+                .addContainerGap(40, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                .addContainerGap(25, Short.MAX_VALUE)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createSequentialGroup()
+                        .add(jLabelUsername)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(jPasswordFieldOld, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                            .add(jLabel2))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(jPasswordFieldNew, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                            .add(jLabel3))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(jPasswordFieldConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                            .add(jLabel4)))
+                    .add(jLabel1))
+                .add(17, 17, 17)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jButtonCancel)
+                    .add(jButtonChangePass))
+                .add(12, 12, 12))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonChangePassActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonChangePassActionPerformed
+        String oldPass = new String(jPasswordFieldOld.getPassword());
+        String newPass = new String(jPasswordFieldNew.getPassword());
+        String confirmPass = new String(jPasswordFieldConfirm.getPassword());
+
+        if (oldPass.length() == 0 || newPass.length() == 0 || confirmPass.length() == 0) {
+            JOptionPane.showMessageDialog(this, "Password must have characters!",
+                    "Password Empty", JOptionPane.ERROR_MESSAGE);
+
+            return;
+        }
+         if (!newPass.equals(confirmPass)) {
+            JOptionPane.showMessageDialog(this, "Passwords must be equal!",
+                    "Diferent Passwords", JOptionPane.ERROR_MESSAGE);
+
+            return;
+        }
+
+        String oldPassHash = HashService.getSHA1Hash(oldPass);
+        String newPassHash = HashService.getSHA1Hash(newPass);
+
+        try {
+            if (!user.changePassword(oldPassHash, newPassHash)) {
+                JOptionPane.showMessageDialog(this, "Old Password is wrong!",
+                    "Wrong Password", JOptionPane.ERROR_MESSAGE);
+
+            return;
+            }
+            else{
+                JOptionPane.showMessageDialog(this, "Password successfully changed!",
+                    "Password Changed", JOptionPane.INFORMATION_MESSAGE);
+            }
+        } catch (RemoteException ex) {
+            JOptionPane.showMessageDialog(this, "Its impossible to change the password at this time!",
+                    "Connectivity error", JOptionPane.ERROR_MESSAGE);
+        }
+    }//GEN-LAST:event_jButtonChangePassActionPerformed
+
+    private void jButtonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCancelActionPerformed
+        this.dispose();
+    }//GEN-LAST:event_jButtonCancelActionPerformed
+
+    private void jPasswordFieldOldKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jPasswordFieldOldKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            jButtonChangePass.doClick();
+    }//GEN-LAST:event_jPasswordFieldOldKeyPressed
+
+    private void jPasswordFieldNewKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jPasswordFieldNewKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            jButtonChangePass.doClick();
+    }//GEN-LAST:event_jPasswordFieldNewKeyPressed
+
+    private void jPasswordFieldConfirmKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jPasswordFieldConfirmKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            jButtonChangePass.doClick();
+    }//GEN-LAST:event_jPasswordFieldConfirmKeyPressed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonCancel;
+    private javax.swing.JButton jButtonChangePass;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabelUsername;
+    private javax.swing.JPasswordField jPasswordFieldConfirm;
+    private javax.swing.JPasswordField jPasswordFieldNew;
+    private javax.swing.JPasswordField jPasswordFieldOld;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.form
new file mode 100755
index 0000000..3082590
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.form
@@ -0,0 +1,354 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Client Options"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[453, 311]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jTabbedPane1" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jButtonWrite" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jButtonClose" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
+              <Component id="jTabbedPane1" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButtonWrite" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonClose" alignment="3" min="-2" pref="38" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+      <Properties>
+        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[0, 0]"/>
+        </Property>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Directory Settings">
+                <Property name="tabTitle" type="java.lang.String" value="Directory Settings"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel23" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel34" min="-2" pref="20" max="-2" attributes="0"/>
+                              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                              <Component id="jButtoViewerPath" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jButtonRemoveEV" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Component id="jLabelExternalViewer" alignment="0" pref="431" max="32767" attributes="0"/>
+                          <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabelTempFilesDir" alignment="1" pref="459" max="32767" attributes="0"/>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel35" min="-2" pref="20" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                              <Component id="jButtonTempDir" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabel23" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabelExternalViewer" min="-2" pref="18" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                              <Component id="jButtoViewerPath" alignment="3" min="-2" max="-2" attributes="0"/>
+                              <Component id="jButtonRemoveEV" alignment="3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Component id="jLabel34" alignment="0" min="-2" pref="22" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabelTempFilesDir" min="-2" pref="18" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jButtonTempDir" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel35" min="-2" pref="22" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace pref="29" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel34">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("aboutico.gif"))" type="code"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jLabel34MouseClicked"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabelExternalViewer">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="<External Viewer Path>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtoViewerPath">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Change External Viewer Path"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtoViewerPathActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel23">
+              <Properties>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Grande" size="13" style="1"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="External Viewer Path:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Grande" size="13" style="1"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Temporary Files Directory: "/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabelTempFilesDir">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="<Temporary Files Directory>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel35">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("aboutico.gif"))" type="code"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jLabel35MouseClicked"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonTempDir">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Change External Viewer Path"/>
+                <Property name="actionCommand" type="java.lang.String" value="Change Temporary Dir"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonTempDirActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonRemoveEV">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Remove E.V."/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonRemoveEVActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Default GUI Server">
+                <Property name="tabTitle" type="java.lang.String" value="Default GUI Server"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel5" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel6" alignment="0" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="Password" pref="169" max="32767" attributes="1"/>
+                                  <Component id="Username" alignment="0" pref="151" max="32767" attributes="1"/>
+                                  <Component id="Port" alignment="0" pref="151" max="32767" attributes="1"/>
+                                  <Component id="Host" alignment="0" pref="151" max="32767" attributes="1"/>
+                              </Group>
+                              <EmptySpace min="-2" pref="163" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jCheckBoxAutoConnect" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace pref="272" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Host" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Port" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Username" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Password" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jCheckBoxAutoConnect" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Port:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="Port">
+              <Events>
+                <EventHandler event="focusLost" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="PortFocusLost"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Host:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="Host">
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Grande" size="13" style="1"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Default GUI Server:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel5">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Username:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="Username">
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel6">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Password:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JPasswordField" name="Password">
+              <Events>
+                <EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="PasswordFocusGained"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JCheckBox" name="jCheckBoxAutoConnect">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="AutoConnect at Startup"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonWrite">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("floopy-icon.png"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Save Configurations"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonWriteActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonClose">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Close"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonCloseActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.java
new file mode 100755
index 0000000..7dcac9a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ClientOptions.java
@@ -0,0 +1,485 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ClientOptions.java
+ *
+ * Created on 4/Mai/2010, 13:03:33
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.core.ClientSettings;
+import pt.ua.dicoogle.core.XMLClientSupport;
+import pt.ua.dicoogle.server.users.HashService;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at Deprecated
+public class ClientOptions extends javax.swing.JFrame {
+    private ClientSettings settings;
+
+    private static ClientOptions instance = null;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized ClientOptions getInstance()
+    {
+        try
+        {
+            sem.acquire();
+            if (instance == null)
+            {
+                instance = new ClientOptions();
+            }
+            sem.release();
+
+        }
+        catch (InterruptedException ex)
+        {
+            LoggerFactory.getLogger(ClientOptions.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+    public static Image getImage(final String pathAndFileName) {
+           final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+           return Toolkit.getDefaultToolkit().getImage(url);
+       }
+
+    /** Creates new form ClientOptions */
+    private ClientOptions() {
+        initComponents();
+
+        
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        settings = ClientSettings.getInstance();
+
+        jLabelExternalViewer.setText(settings.getExtV());
+        Host.setText(settings.getDefaultServerHost());
+        Port.setText(String.valueOf(settings.getDefaultServerPort()));
+        Username.setText(settings.getDefaultUserName());
+        jLabelTempFilesDir.setText(settings.getTempFilesDir());
+
+        if(settings.getDefaultPassword() != null && !settings.getDefaultPassword().equals(""))
+            Password.setText("lixo_lixo_lixo");
+
+        jCheckBoxAutoConnect.setSelected(settings.getAutoConnect());
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jTabbedPane1 = new javax.swing.JTabbedPane();
+        jPanel1 = new javax.swing.JPanel();
+        jLabel34 = new javax.swing.JLabel();
+        jLabelExternalViewer = new javax.swing.JLabel();
+        jButtoViewerPath = new javax.swing.JButton();
+        jLabel23 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jLabelTempFilesDir = new javax.swing.JLabel();
+        jLabel35 = new javax.swing.JLabel();
+        jButtonTempDir = new javax.swing.JButton();
+        jButtonRemoveEV = new javax.swing.JButton();
+        jPanel2 = new javax.swing.JPanel();
+        jLabel4 = new javax.swing.JLabel();
+        Port = new javax.swing.JTextField();
+        jLabel1 = new javax.swing.JLabel();
+        Host = new javax.swing.JTextField();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        Username = new javax.swing.JTextField();
+        jLabel6 = new javax.swing.JLabel();
+        Password = new javax.swing.JPasswordField();
+        jCheckBoxAutoConnect = new javax.swing.JCheckBox();
+        jButtonWrite = new javax.swing.JButton();
+        jButtonClose = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Client Options");
+        setMinimumSize(new java.awt.Dimension(453, 311));
+
+        jTabbedPane1.setMinimumSize(new java.awt.Dimension(0, 0));
+
+        jLabel34.setIcon(new ImageIcon(getImage("aboutico.gif")));
+        jLabel34.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jLabel34MouseClicked(evt);
+            }
+        });
+
+        jLabelExternalViewer.setText("<External Viewer Path>");
+
+        jButtoViewerPath.setText("Change External Viewer Path");
+        jButtoViewerPath.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtoViewerPathActionPerformed(evt);
+            }
+        });
+
+        jLabel23.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
+        jLabel23.setText("External Viewer Path:");
+
+        jLabel3.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
+        jLabel3.setText("Temporary Files Directory: ");
+
+        jLabelTempFilesDir.setText("<Temporary Files Directory>");
+
+        jLabel35.setIcon(new ImageIcon(getImage("aboutico.gif")));
+        jLabel35.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jLabel35MouseClicked(evt);
+            }
+        });
+
+        jButtonTempDir.setText("Change External Viewer Path");
+        jButtonTempDir.setActionCommand("Change Temporary Dir");
+        jButtonTempDir.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonTempDirActionPerformed(evt);
+            }
+        });
+
+        jButtonRemoveEV.setText("Remove E.V.");
+        jButtonRemoveEV.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonRemoveEVActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jLabel23)
+                    .add(jPanel1Layout.createSequentialGroup()
+                        .add(jLabel34, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 20, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                        .add(jButtoViewerPath)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonRemoveEV))
+                    .add(jLabelExternalViewer, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 431, Short.MAX_VALUE)
+                    .add(jLabel3)
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabelTempFilesDir, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 459, Short.MAX_VALUE)
+                    .add(jPanel1Layout.createSequentialGroup()
+                        .add(jLabel35, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 20, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .add(18, 18, 18)
+                        .add(jButtonTempDir)))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel23)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jLabelExternalViewer, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 18, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                        .add(jButtoViewerPath)
+                        .add(jButtonRemoveEV))
+                    .add(jLabel34, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .add(18, 18, 18)
+                .add(jLabel3)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jLabelTempFilesDir, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 18, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .add(8, 8, 8)
+                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jButtonTempDir)
+                    .add(jLabel35, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(29, Short.MAX_VALUE))
+        );
+
+        jTabbedPane1.addTab("Directory Settings", jPanel1);
+
+        jLabel4.setText("Port:");
+
+        Port.addFocusListener(new java.awt.event.FocusAdapter() {
+            public void focusLost(java.awt.event.FocusEvent evt) {
+                PortFocusLost(evt);
+            }
+        });
+
+        jLabel1.setText("Host:");
+
+        jLabel2.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
+        jLabel2.setText("Default GUI Server:");
+
+        jLabel5.setText("Username:");
+
+        jLabel6.setText("Password:");
+
+        Password.addFocusListener(new java.awt.event.FocusAdapter() {
+            public void focusGained(java.awt.event.FocusEvent evt) {
+                PasswordFocusGained(evt);
+            }
+        });
+
+        jCheckBoxAutoConnect.setText("AutoConnect at Startup");
+
+        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jPanel2Layout.createSequentialGroup()
+                        .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel1)
+                            .add(jLabel4)
+                            .add(jLabel2)
+                            .add(jLabel5)
+                            .add(jLabel6))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(Password, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 169, Short.MAX_VALUE)
+                            .add(Username, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE)
+                            .add(Port, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE)
+                            .add(Host, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 151, Short.MAX_VALUE))
+                        .add(163, 163, 163))
+                    .add(jPanel2Layout.createSequentialGroup()
+                        .add(jCheckBoxAutoConnect)
+                        .addContainerGap(272, Short.MAX_VALUE))))
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel2)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel1)
+                    .add(Host, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel4)
+                    .add(Port, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel5)
+                    .add(Username, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel6)
+                    .add(Password, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jCheckBoxAutoConnect)
+                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jTabbedPane1.addTab("Default GUI Server", jPanel2);
+
+        jButtonWrite.setIcon(new ImageIcon(getImage("floopy-icon.png")));
+        jButtonWrite.setText("Save Configurations");
+        jButtonWrite.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonWriteActionPerformed(evt);
+            }
+        });
+
+        jButtonClose.setText("Close");
+        jButtonClose.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonCloseActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createSequentialGroup()
+                        .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addContainerGap())
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(jButtonWrite)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                        .add(jButtonClose)
+                        .add(18, 18, 18))))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(23, 23, 23)
+                .add(jTabbedPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jButtonWrite)
+                    .add(jButtonClose, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 38, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonWriteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonWriteActionPerformed
+        saveSettings();
+}//GEN-LAST:event_jButtonWriteActionPerformed
+
+    private void jButtonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCloseActionPerformed
+        this.dispatchEvent(new java.awt.event.WindowEvent(this, java.awt.Event.WINDOW_DESTROY));
+}//GEN-LAST:event_jButtonCloseActionPerformed
+
+    private void jLabel34MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabel34MouseClicked
+        JOptionPane.showMessageDialog(this, "The external viewer path sets the aplication that Dicoogle Client will use to open DICOM files", "Did you know?", JOptionPane.INFORMATION_MESSAGE);
+}//GEN-LAST:event_jLabel34MouseClicked
+
+    private void jButtoViewerPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtoViewerPathActionPerformed
+        JFileChooser chooser = new JFileChooser(); 
+         chooser.setCurrentDirectory(new java.io.File("."));
+         chooser.setDialogTitle("External Viewer Path");
+         chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+         chooser.setAcceptAllFileFilterUsed(false);
+
+         if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
+         {
+             jLabelExternalViewer.setText(chooser.getSelectedFile().toString());
+             jLabelExternalViewer.setToolTipText(jLabelExternalViewer.getText());
+        }
+}//GEN-LAST:event_jButtoViewerPathActionPerformed
+
+    private void PortFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_PortFocusLost
+        try {
+            Integer.valueOf(Port.getText());
+        } catch (NumberFormatException ex) {
+            JOptionPane.showMessageDialog(this, "Only numbers are accepted!",
+                    "Invalid Input", JOptionPane.ERROR_MESSAGE);
+
+            Port.grabFocus();
+        }
+    }//GEN-LAST:event_PortFocusLost
+
+    private void jLabel35MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jLabel35MouseClicked
+        JOptionPane.showMessageDialog(this, "The temporary files directory sets the directory that Dicoogle Client will use to save temporary DICOM files", "Did you know?", JOptionPane.INFORMATION_MESSAGE);
+    }//GEN-LAST:event_jLabel35MouseClicked
+
+    private void jButtonTempDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonTempDirActionPerformed
+        JFileChooser chooser = new JFileChooser();
+        chooser.setCurrentDirectory(new java.io.File("."));
+        chooser.setDialogTitle("Temporary Files Directory");
+        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+        chooser.setAcceptAllFileFilterUsed(false);
+
+        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
+        {
+             jLabelTempFilesDir.setText(chooser.getSelectedFile().toString());
+             jLabelTempFilesDir.setToolTipText(jLabelTempFilesDir.getText());
+        }
+    }//GEN-LAST:event_jButtonTempDirActionPerformed
+
+    private void PasswordFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_PasswordFocusGained
+        String pass = new String(Password.getPassword());
+
+        if(pass.equals("lixo_lixo_lixo"))
+            Password.setText("");
+    }//GEN-LAST:event_PasswordFocusGained
+
+    private void jButtonRemoveEVActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonRemoveEVActionPerformed
+        jLabelExternalViewer.setText("");
+    }//GEN-LAST:event_jButtonRemoveEVActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JTextField Host;
+    private javax.swing.JPasswordField Password;
+    private javax.swing.JTextField Port;
+    private javax.swing.JTextField Username;
+    private javax.swing.JButton jButtoViewerPath;
+    private javax.swing.JButton jButtonClose;
+    private javax.swing.JButton jButtonRemoveEV;
+    private javax.swing.JButton jButtonTempDir;
+    private javax.swing.JButton jButtonWrite;
+    private javax.swing.JCheckBox jCheckBoxAutoConnect;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel23;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel34;
+    private javax.swing.JLabel jLabel35;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel6;
+    private javax.swing.JLabel jLabelExternalViewer;
+    private javax.swing.JLabel jLabelTempFilesDir;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JTabbedPane jTabbedPane1;
+    // End of variables declaration//GEN-END:variables
+
+    public boolean unsavedSettings(){
+        if(!jLabelExternalViewer.getText().equals(settings.getExtV())
+                || !Host.getText().equals(settings.getDefaultServerHost())
+                || Integer.valueOf(Port.getText()) != settings.getDefaultServerPort()
+                || !Username.getText().equals(settings.getDefaultUserName())
+                || !jLabelTempFilesDir.getText().equals(settings.getTempFilesDir())
+                || jCheckBoxAutoConnect.isSelected() != settings.getAutoConnect())
+            return true;
+        
+        String pass = new String(Password.getPassword());
+
+        if(!pass.equals("lixo_lixo_lixo") && !HashService.getSHA1Hash(pass).equals(settings.getDefaultPassword()))
+            return true;
+
+        return false;
+    }
+
+    public void saveSettings(){
+        // save settings to ClientSettings
+        settings.setExtV(jLabelExternalViewer.getText());
+        settings.setDefaultServerHost(Host.getText());
+        settings.setDefaultServerPort(Integer.valueOf(Port.getText()));
+        settings.setDefaultUserName(Username.getText());
+        settings.setTempFilesDir(jLabelTempFilesDir.getText());
+
+        String pass = new String(Password.getPassword());
+        
+        if(!pass.equals("lixo_lixo_lixo"))
+            settings.setDefaultPassword(HashService.getSHA1Hash(pass));
+
+        settings.setAutoConnect(jCheckBoxAutoConnect.isSelected());
+
+        // save settings to xml
+        XMLClientSupport xmlClient = new XMLClientSupport();
+        xmlClient.printXML();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.form
new file mode 100755
index 0000000..df81cf5
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.form
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" value="Dicoogle GUI Connector"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel6" min="-2" pref="255" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="33" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace pref="218" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="103" alignment="0" groupAlignment="1" attributes="0">
+                              <Group type="102" alignment="1" attributes="0">
+                                  <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace pref="81" max="32767" attributes="0"/>
+                                  <Component id="ConnectButton" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="1" attributes="0">
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="Pass" pref="185" max="32767" attributes="0"/>
+                                      <Component id="Host" alignment="0" pref="185" max="32767" attributes="1"/>
+                                      <Component id="Port" alignment="0" pref="185" max="32767" attributes="0"/>
+                                      <Component id="User" alignment="0" pref="185" max="32767" attributes="1"/>
+                                  </Group>
+                              </Group>
+                          </Group>
+                      </Group>
+                      <EmptySpace min="-2" pref="80" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" attributes="0">
+                      <Component id="jLabel7" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="202" max="-2" attributes="0"/>
+              <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="222" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+              <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jLabel6" pref="231" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jLabel7" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="22" max="32767" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="Host" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Port" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="User" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                          <Component id="Pass" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="ConnectButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="37" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel4">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Port:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="Port">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="PortKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Host:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="ConnectButton">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Connect"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ConnectButtonActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="User:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Pass:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="Host">
+      <Events>
+        <EventHandler event="keyTyped" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="HostKeyTyped"/>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="HostKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JTextField" name="User">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="UserKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JPasswordField" name="Pass">
+      <Events>
+        <EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="PassFocusGained"/>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="PassKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel5">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="17" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Dicoogle GUI Connector"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel6">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("icone_dicoogle_small.png"))" type="code"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel7">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Version 0.5ALPHA"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel8">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("ajax-loader.gif"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Connecting..."/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.java
new file mode 100755
index 0000000..f1cbdf6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ConnectWindow.java
@@ -0,0 +1,403 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.net.URL;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import org.jvnet.substance.SubstanceLookAndFeel;
+import org.jvnet.substance.skin.BusinessBlackSteelSkin;
+
+
+import pt.ua.dicoogle.rGUI.client.ConnectServer;
+
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.ClientSettings;
+import pt.ua.dicoogle.server.users.HashService;
+
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class ConnectWindow extends javax.swing.JFrame {
+
+    private static ConnectWindow instance;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    private boolean isUsingDefaultPass = false;
+
+    public static synchronized ConnectWindow getInstance()
+    {
+        try
+        {
+            sem.acquire();
+            if (instance == null)
+            {
+                instance = new ConnectWindow();
+            }
+            sem.release();
+        }
+        catch (InterruptedException ex)
+        {
+            LoggerFactory.getLogger(ConnectWindow.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+
+    public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+    
+    
+    /** Creates new form ConnectWindow */
+    private ConnectWindow() {
+        
+        initComponents();
+        // change to Dicoogle Default Skin
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+                SubstanceLookAndFeel.setSkin(new BusinessBlackSteelSkin());
+            }
+        });
+
+        Image image = getImage("trayicon.gif");
+        this.setIconImage(image);
+
+        // Positions the window in the center of screen
+        int width = this.getWidth();
+        int height = this.getHeight();
+        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+        int x = (screen.width-width)/2;
+        int y = (screen.height-height)/2;
+        setBounds(x,y,width,height);
+        
+        
+        jLabel8.setVisible(false);
+
+        ClientSettings settings = ClientSettings.getInstance();
+        Host.setText(settings.getDefaultServerHost());
+        Port.setText(String.valueOf(settings.getDefaultServerPort()));
+        User.setText(settings.getDefaultUserName());
+
+        if(settings.getDefaultPassword() != null && !settings.getDefaultPassword().equals(""))
+        {
+            Pass.setText("lixo_lixo_lixo");
+            isUsingDefaultPass = true;
+            ConnectButton.grabFocus();
+        }
+        else
+            Pass.grabFocus();
+        
+        if(Main.isFixedClient()){
+            Host.setEnabled(false);
+            Port.setEnabled(false);
+            Port.setText(Main.getRemoteGUIPort() + "");
+        }
+
+        //this.setVisible(true);
+
+        // set this window visible
+       SwingUtilities.invokeLater(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                ConnectWindow.getInstance().setVisible(true);
+
+                if(ClientSettings.getInstance().getAutoConnect())
+                    ConnectWindow.getInstance().ConnectButtonActionPerformed(null);
+            }
+        });
+       
+
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel4 = new javax.swing.JLabel();
+        Port = new javax.swing.JTextField();
+        jLabel1 = new javax.swing.JLabel();
+        ConnectButton = new javax.swing.JButton();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        Host = new javax.swing.JTextField();
+        User = new javax.swing.JTextField();
+        Pass = new javax.swing.JPasswordField();
+        jLabel5 = new javax.swing.JLabel();
+        jLabel6 = new javax.swing.JLabel();
+        jLabel7 = new javax.swing.JLabel();
+        jLabel8 = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        setTitle("Dicoogle GUI Connector");
+        setResizable(false);
+
+        jLabel4.setText("Port:");
+
+        Port.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                PortKeyPressed(evt);
+            }
+        });
+
+        jLabel1.setText("Host:");
+
+        ConnectButton.setText("Connect");
+        ConnectButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ConnectButtonActionPerformed(evt);
+            }
+        });
+
+        jLabel2.setText("User:");
+
+        jLabel3.setText("Pass:");
+
+        Host.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyTyped(java.awt.event.KeyEvent evt) {
+                HostKeyTyped(evt);
+            }
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                HostKeyPressed(evt);
+            }
+        });
+
+        User.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                UserKeyPressed(evt);
+            }
+        });
+
+        Pass.addFocusListener(new java.awt.event.FocusAdapter() {
+            public void focusGained(java.awt.event.FocusEvent evt) {
+                PassFocusGained(evt);
+            }
+        });
+        Pass.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                PassKeyPressed(evt);
+            }
+        });
+
+        jLabel5.setFont(new java.awt.Font("Lucida Grande", 1, 17)); // NOI18N
+        jLabel5.setText("Dicoogle GUI Connector");
+
+        jLabel6.setIcon(new ImageIcon(getImage("icone_dicoogle_small.png")));
+
+        jLabel7.setText("Version 0.5ALPHA");
+
+        jLabel8.setIcon(new ImageIcon(getImage("ajax-loader.gif")));
+        jLabel8.setText("Connecting...");
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel6, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 255, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .add(33, 33, 33)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(layout.createSequentialGroup()
+                                .add(jLabel4)
+                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 218, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                                .add(layout.createSequentialGroup()
+                                    .add(jLabel8)
+                                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 81, Short.MAX_VALUE)
+                                    .add(ConnectButton))
+                                .add(layout.createSequentialGroup()
+                                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                        .add(jLabel2)
+                                        .add(jLabel3)
+                                        .add(jLabel1))
+                                    .add(28, 28, 28)
+                                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                        .add(Pass, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)
+                                        .add(Host, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)
+                                        .add(Port, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)
+                                        .add(User, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)))))
+                        .add(80, 80, 80))
+                    .add(layout.createSequentialGroup()
+                        .add(jLabel7)
+                        .addContainerGap())))
+            .add(layout.createSequentialGroup()
+                .add(202, 202, 202)
+                .add(jLabel5)
+                .addContainerGap(222, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                .add(20, 20, 20)
+                .add(jLabel5)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(jLabel6, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 231, Short.MAX_VALUE)
+                        .addContainerGap())
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(jLabel7)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 22, Short.MAX_VALUE)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(Host, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                            .add(jLabel1))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(jLabel4)
+                            .add(Port, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                        .add(12, 12, 12)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel2)
+                            .add(User, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel3)
+                            .add(Pass, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(ConnectButton)
+                            .add(jLabel8))
+                        .add(37, 37, 37))))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void ConnectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ConnectButtonActionPerformed
+        if (Host.getText().length() == 0 || Port.getText().length() == 0
+                || Pass.getPassword().length == 0 || User.getText().length() == 0)
+        {
+            JOptionPane.showMessageDialog(this, "You need to fill in all fields!",
+                    "Error", JOptionPane.INFORMATION_MESSAGE);
+            
+        }
+        else{
+            jLabel8.setVisible(true);
+            
+            try{
+                
+                ConnectServer connect;
+                try {
+                    
+                    connect = new ConnectServer(Host.getText(), Integer.valueOf(Port.getText()));
+                    
+                    String passwordHash;
+                    if(isUsingDefaultPass){
+                        passwordHash = ClientSettings.getInstance().getDefaultPassword();
+                    }
+                    else{
+                        String passPlainText = new String(Pass.getPassword());
+                        passwordHash = HashService.getSHA1Hash(passPlainText);
+                    }
+                    if (!connect.login(User.getText(), passwordHash)) {
+                        jLabel8.setVisible(false);
+                        JOptionPane.showMessageDialog(this, "The username or password is wrong!", "Wrong Username or Password", JOptionPane.ERROR_MESSAGE);
+                    }
+                    
+
+                } catch (Exception ex) {
+                   //LoggerFactory.getLogger(ConnectWindow.class).error(ex.getMessage(), ex);
+                    JOptionPane.showMessageDialog(this, "Unable to connect to the GUI Server\n"+ex.getMessage(),
+                    "Connection Error", JOptionPane.ERROR_MESSAGE);
+                    ex.printStackTrace();
+                }
+                
+            }
+            catch(NumberFormatException ex){
+                jLabel8.setVisible(false);
+
+                JOptionPane.showMessageDialog(this, "Wrong port number!",
+                    "Error", JOptionPane.ERROR_MESSAGE);
+            }
+
+        }
+}//GEN-LAST:event_ConnectButtonActionPerformed
+
+    private void HostKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_HostKeyTyped
+
+    }//GEN-LAST:event_HostKeyTyped
+
+    private void HostKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_HostKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            ConnectButton.doClick();
+    }//GEN-LAST:event_HostKeyPressed
+
+    private void PortKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_PortKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            ConnectButton.doClick();
+    }//GEN-LAST:event_PortKeyPressed
+
+    private void UserKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_UserKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            ConnectButton.doClick();
+    }//GEN-LAST:event_UserKeyPressed
+
+    private void PassKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_PassKeyPressed
+        if(evt.getKeyCode() == KeyEvent.VK_ENTER)
+            ConnectButton.doClick();
+    }//GEN-LAST:event_PassKeyPressed
+
+    private void PassFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_PassFocusGained
+        if(isUsingDefaultPass){
+            Pass.setText("");
+            isUsingDefaultPass = false;
+        }
+    }//GEN-LAST:event_PassFocusGained
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton ConnectButton;
+    private javax.swing.JTextField Host;
+    private javax.swing.JPasswordField Pass;
+    private javax.swing.JTextField Port;
+    private javax.swing.JTextField User;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel6;
+    private javax.swing.JLabel jLabel7;
+    private javax.swing.JLabel jLabel8;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.form
new file mode 100755
index 0000000..5d7c20d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.form
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.7" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Send"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanelVBox" min="-2" pref="567" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
+              <Component id="jPanelVBox" min="-2" pref="264" max="-2" attributes="0"/>
+              <EmptySpace pref="24" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanelVBox">
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+        <Property name="axis" type="int" value="3"/>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanelSenderBox">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jPanelfields" min="-2" pref="283" max="-2" attributes="0"/>
+                          </Group>
+                          <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jScrollPane2" min="-2" pref="254" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Component id="jPanelfields" min="-2" pref="70" max="-2" attributes="0"/>
+                      <EmptySpace pref="56" max="32767" attributes="0"/>
+                      <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jScrollPane2" min="-2" pref="122" max="-2" attributes="0"/>
+                      <EmptySpace pref="15" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="jPanelfields">
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
+                <Property name="columns" type="int" value="2"/>
+                <Property name="rows" type="int" value="3"/>
+              </Layout>
+              <SubComponents>
+                <Component class="javax.swing.JLabel" name="jLabelAETitle">
+                  <Properties>
+                    <Property name="horizontalAlignment" type="int" value="4"/>
+                    <Property name="text" type="java.lang.String" value="AETitle"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JTextField" name="jTextFieldAETitle">
+                  <Properties>
+                    <Property name="editable" type="boolean" value="false"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JLabel" name="jLabelIP">
+                  <Properties>
+                    <Property name="horizontalAlignment" type="int" value="4"/>
+                    <Property name="text" type="java.lang.String" value="IP:"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JTextField" name="jTextFieldIP">
+                  <Properties>
+                    <Property name="editable" type="boolean" value="false"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JLabel" name="jLabelPort">
+                  <Properties>
+                    <Property name="horizontalAlignment" type="int" value="4"/>
+                    <Property name="text" type="java.lang.String" value="Port:"/>
+                  </Properties>
+                </Component>
+                <Component class="javax.swing.JTextField" name="jTextFieldPort">
+                  <Properties>
+                    <Property name="editable" type="boolean" value="false"/>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTree" name="jTree1">
+                  <Properties>
+                    <Property name="model" type="javax.swing.tree.TreeModel" editor="org.netbeans.modules.form.editors2.TreeModelEditor">
+                      <TreeModel code=""/>
+                    </Property>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="valueChanged" listener="javax.swing.event.TreeSelectionListener" parameters="javax.swing.event.TreeSelectionEvent" handler="jTree1ValueChanged"/>
+                  </Events>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="DICOM Files to be send:"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanelDICOMObjects">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+            <Property name="axis" type="int" value="1"/>
+          </Layout>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanelButtons">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JList" name="jListFiles">
+              <Properties>
+                <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+                  <StringArray count="0"/>
+                </Property>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JList(model)"/>
+                <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="DefaultListModel model = new DefaultListModel();"/>
+              </AuxValues>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Component class="javax.swing.JButton" name="jButtonSend">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Send"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonSendActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.java
new file mode 100755
index 0000000..42c29d9
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/DicomSend.java
@@ -0,0 +1,356 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JOptionPane;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDicomSend;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class DicomSend extends javax.swing.JFrame {
+
+    private ArrayList<String> filePaths;
+    private ArrayList<MoveDestination> dest;
+    private Hashtable<String, MoveDestination> destHash = new Hashtable<String, MoveDestination>();
+
+    private IDicomSend dmSend;
+
+    /** Creates new form DicomSend */
+    public DicomSend(ArrayList<String> filePaths) {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        this.filePaths = filePaths;
+
+        dmSend = UserRefs.getInstance().getDicomSend();
+        
+        jLabel1.setText(filePaths.size() + " DICOM Files to be send:");
+
+        fillStorageServerTree();
+
+        if (filePaths != null)
+            fillList();
+    }
+
+    /* Fill the Storage Server Tree */
+    private void fillStorageServerTree() {
+        try {
+            /* Uses the Storage Server Destinations of Query/Retrive System*/
+            dest = dmSend.getDestinations();
+
+            DefaultMutableTreeNode treeNodeRoot = new DefaultMutableTreeNode("Storage Servers");
+
+            if (dest.size() != 0) {
+                Iterator<MoveDestination> itDest = dest.iterator();
+
+                MoveDestination m;
+                DefaultMutableTreeNode treeNode;
+
+                while (itDest.hasNext()) {
+                    m = itDest.next();
+                    destHash.put(m.getAETitle(), m);
+
+                    treeNode = new DefaultMutableTreeNode(m.getAETitle());
+
+                    treeNode.add(new DefaultMutableTreeNode("AETitle: " + m.getAETitle()));
+                    treeNode.add(new DefaultMutableTreeNode("IP: " + m.getIpAddrs()));
+                    treeNode.add(new DefaultMutableTreeNode("Port: " + m.getPort()));
+                    
+                    treeNodeRoot.add(treeNode);
+                }
+            }
+
+            jTree1.setModel(new javax.swing.tree.DefaultTreeModel(treeNodeRoot));
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(DicomSend.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    /** Fill the Objects to Send Tree with patients, studies, series and images */
+    private void fillList() {
+        DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode("root");
+
+        DefaultListModel model = (DefaultListModel) jListFiles.getModel();
+
+        Iterator<String> it = filePaths.iterator();
+
+        while(it.hasNext())
+            model.addElement(it.next());
+
+        jListFiles.setModel(model);
+    }
+
+    /**
+     * @return the selcted Server to move data
+     */
+    private MoveDestination getSelectedDestination() {
+        TreePath path = jTree1.getSelectionPath();
+
+        if (path != null && path.getPathCount() > 1) {
+            return destHash.get(path.getPathComponent(1).toString());
+        }
+
+        return null;
+    }
+
+    /*
+    private ArrayList<String> getAllImages() {
+        if (dimGen == null) {
+            return null;
+        }
+
+        ArrayList<String> images = new ArrayList<String>();
+
+        Iterator<Patient> it = dimGen.getPatients().iterator();
+
+        while (it.hasNext()) {
+            Patient patient = it.next();
+
+            Iterator<Study> itStudy = patient.getStudies().iterator();
+
+            while (itStudy.hasNext()) {
+                Study study = itStudy.next();
+
+                Iterator<Serie> itSerie = study.getSeries().iterator();
+
+                while (itSerie.hasNext()) {
+                    Serie serie = itSerie.next();
+
+                    images.addAll(serie.getImageList());
+                }
+            }
+        }
+
+        return images;
+    }
+     *
+     */
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanelVBox = new javax.swing.JPanel();
+        jPanelSenderBox = new javax.swing.JPanel();
+        jPanelfields = new javax.swing.JPanel();
+        jLabelAETitle = new javax.swing.JLabel();
+        jTextFieldAETitle = new javax.swing.JTextField();
+        jLabelIP = new javax.swing.JLabel();
+        jTextFieldIP = new javax.swing.JTextField();
+        jLabelPort = new javax.swing.JLabel();
+        jTextFieldPort = new javax.swing.JTextField();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jTree1 = new javax.swing.JTree();
+        jLabel1 = new javax.swing.JLabel();
+        jPanelDICOMObjects = new javax.swing.JPanel();
+        jPanelButtons = new javax.swing.JPanel();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        DefaultListModel model = new DefaultListModel();
+        jListFiles = new javax.swing.JList(model);
+        jButtonSend = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Send");
+        setResizable(false);
+
+        jPanelVBox.setLayout(new javax.swing.BoxLayout(jPanelVBox, javax.swing.BoxLayout.PAGE_AXIS));
+
+        jPanelfields.setLayout(new java.awt.GridLayout(3, 2));
+
+        jLabelAETitle.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        jLabelAETitle.setText("AETitle");
+        jPanelfields.add(jLabelAETitle);
+
+        jTextFieldAETitle.setEditable(false);
+        jPanelfields.add(jTextFieldAETitle);
+
+        jLabelIP.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        jLabelIP.setText("IP:");
+        jPanelfields.add(jLabelIP);
+
+        jTextFieldIP.setEditable(false);
+        jPanelfields.add(jTextFieldIP);
+
+        jLabelPort.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        jLabelPort.setText("Port:");
+        jPanelfields.add(jLabelPort);
+
+        jTextFieldPort.setEditable(false);
+        jPanelfields.add(jTextFieldPort);
+
+        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
+        jTree1.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
+        jTree1.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
+            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
+                jTree1ValueChanged(evt);
+            }
+        });
+        jScrollPane2.setViewportView(jTree1);
+
+        jLabel1.setText("DICOM Files to be send:");
+
+        javax.swing.GroupLayout jPanelSenderBoxLayout = new javax.swing.GroupLayout(jPanelSenderBox);
+        jPanelSenderBox.setLayout(jPanelSenderBoxLayout);
+        jPanelSenderBoxLayout.setHorizontalGroup(
+            jPanelSenderBoxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanelSenderBoxLayout.createSequentialGroup()
+                .addGroup(jPanelSenderBoxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanelSenderBoxLayout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(jPanelfields, javax.swing.GroupLayout.PREFERRED_SIZE, 283, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(jLabel1))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 254, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        jPanelSenderBoxLayout.setVerticalGroup(
+            jPanelSenderBoxLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanelSenderBoxLayout.createSequentialGroup()
+                .addComponent(jPanelfields, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 56, Short.MAX_VALUE)
+                .addComponent(jLabel1))
+            .addGroup(jPanelSenderBoxLayout.createSequentialGroup()
+                .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jPanelVBox.add(jPanelSenderBox);
+
+        jPanelDICOMObjects.setLayout(new javax.swing.BoxLayout(jPanelDICOMObjects, javax.swing.BoxLayout.Y_AXIS));
+        jPanelVBox.add(jPanelDICOMObjects);
+
+        jPanelButtons.setLayout(new javax.swing.BoxLayout(jPanelButtons, javax.swing.BoxLayout.LINE_AXIS));
+        jPanelVBox.add(jPanelButtons);
+
+        jScrollPane1.setViewportView(jListFiles);
+
+        jPanelVBox.add(jScrollPane1);
+
+        jButtonSend.setText("Send");
+        jButtonSend.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonSendActionPerformed(evt);
+            }
+        });
+        jPanelVBox.add(jButtonSend);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanelVBox, javax.swing.GroupLayout.PREFERRED_SIZE, 567, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGap(7, 7, 7)
+                .addComponent(jPanelVBox, javax.swing.GroupLayout.PREFERRED_SIZE, 264, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(24, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonSendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSendActionPerformed
+        try {
+            MoveDestination destination = getSelectedDestination();
+
+            if (destination == null || filePaths.isEmpty()) {
+                JOptionPane.showMessageDialog(this, "You need to choose a destination.", "Destination", JOptionPane.INFORMATION_MESSAGE);
+                return;
+            }
+
+            if (dmSend.sendFiles(destination, filePaths))
+                JOptionPane.showMessageDialog(this, "Sending files to choosed destination.", "Sending files", JOptionPane.INFORMATION_MESSAGE);
+            else
+                JOptionPane.showMessageDialog(this, "Error sending files to choosed destination.", "Error sending files", JOptionPane.ERROR_MESSAGE);
+            
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(DicomSend.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonSendActionPerformed
+
+    private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_jTree1ValueChanged
+        MoveDestination tmp = getSelectedDestination();
+
+        if (tmp != null) {
+            jTextFieldAETitle.setText(tmp.getAETitle());
+            jTextFieldIP.setText(tmp.getIpAddrs());
+            jTextFieldPort.setText(String.valueOf(tmp.getPort()));
+        } else {
+            jTextFieldAETitle.setText("");
+            jTextFieldIP.setText("");
+            jTextFieldPort.setText("");
+        }
+
+    }//GEN-LAST:event_jTree1ValueChanged
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonSend;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabelAETitle;
+    private javax.swing.JLabel jLabelIP;
+    private javax.swing.JLabel jLabelPort;
+    private javax.swing.JList jListFiles;
+    private javax.swing.JPanel jPanelButtons;
+    private javax.swing.JPanel jPanelDICOMObjects;
+    private javax.swing.JPanel jPanelSenderBox;
+    private javax.swing.JPanel jPanelVBox;
+    private javax.swing.JPanel jPanelfields;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JTextField jTextFieldAETitle;
+    private javax.swing.JTextField jTextFieldIP;
+    private javax.swing.JTextField jTextFieldPort;
+    private javax.swing.JTree jTree1;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.form
new file mode 100755
index 0000000..eb0f694
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.form
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" value="Export Query Results"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[679, 387]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace min="-2" pref="612" max="-2" attributes="0"/>
+              <Component id="jLabelExporting" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="101" max="-2" attributes="0"/>
+              <Component id="jButtonExport" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jButtonCancel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
+          </Group>
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jTabbedPaneExport" min="-2" pref="1013" max="-2" attributes="0"/>
+              <EmptySpace pref="32" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jTabbedPaneExport" min="-2" pref="507" max="-2" attributes="0"/>
+              <EmptySpace pref="38" max="32767" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButtonExport" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonCancel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelExporting" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabelExporting">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("ajax-loader.gif"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Exporting..."/>
+      </Properties>
+    </Component>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPaneExport">
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanelBasic">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Basic">
+                <Property name="tabTitle" type="java.lang.String" value="Basic"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="992" max="32767" attributes="0"/>
+                  <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="1" attributes="0">
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="1" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="jTextFieldAvaliableFilter" pref="283" max="32767" attributes="0"/>
+                                      </Group>
+                                      <Component id="jScrollPane1" alignment="1" pref="394" max="32767" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jButtonAdd" alignment="0" pref="184" max="32767" attributes="0"/>
+                                      <Component id="jButtonRemove" alignment="0" pref="184" max="32767" attributes="1"/>
+                                      <Component id="jButtonUp" alignment="0" pref="184" max="32767" attributes="1"/>
+                                      <Component id="jButtonDown" alignment="0" pref="192" max="32767" attributes="1"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jScrollPane2" pref="376" max="32767" attributes="0"/>
+                                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace min="749" pref="749" max="749" attributes="0"/>
+                              </Group>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <EmptySpace min="0" pref="461" max="32767" attributes="0"/>
+                  <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="0" attributes="0">
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="1" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
+                                  <Component id="jButtonAdd" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jButtonRemove" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace pref="182" max="32767" attributes="0"/>
+                                  <Component id="jButtonUp" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jButtonDown" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="1" attributes="0">
+                                  <EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="1" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
+                                          <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                          <Component id="jScrollPane2" pref="301" max="32767" attributes="0"/>
+                                      </Group>
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Group type="103" groupAlignment="3" attributes="0">
+                                              <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                                              <Component id="jTextFieldAvaliableFilter" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                          <EmptySpace min="-2" max="-2" attributes="0"/>
+                                          <Component id="jScrollPane1" pref="299" max="32767" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                              </Group>
+                          </Group>
+                          <EmptySpace min="-2" pref="79" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="jButtonDown">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Down"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonDownActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonUp">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Up"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonUpActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JTextField" name="jTextFieldAvaliableFilter">
+              <Events>
+                <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTextFieldAvaliableFilterKeyReleased"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Tags for export:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Avaliable Tags:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Select Tags to use for export:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonRemove">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="<-"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonRemoveActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonAdd">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="->"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonAddActionPerformed"/>
+              </Events>
+            </Component>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JList" name="jListExportTags">
+                  <Properties>
+                    <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+                      <StringArray count="0"/>
+                    </Property>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JList" name="jListAvaliableTags">
+                  <Properties>
+                    <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+                      <StringArray count="0"/>
+                    </Property>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Expert">
+                <Property name="tabTitle" type="java.lang.String" value="Expert"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
+                              <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jScrollPane3" min="-2" pref="860" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace pref="126" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jScrollPane3" pref="427" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane3">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTextArea" name="jTextAreaTagList">
+                  <Properties>
+                    <Property name="columns" type="int" value="20"/>
+                    <Property name="rows" type="int" value="5"/>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Write Tags to use for export (one per line):"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonExport">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Export Data"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonExportActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonCancel">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Cancel"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonCancelActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.java
new file mode 100755
index 0000000..eda24db
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/ExportData.java
@@ -0,0 +1,595 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.File;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.common.ExtensionFilter;
+import pt.ua.dicoogle.core.ExportDataSupport;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+
+/**
+ * This class is used to select the tags that will be used to export to file
+ *
+ * @author Samuel da Costa Campos <samuelcampos at ua.pt>
+ *
+ */
+ at Deprecated
+public class ExportData extends javax.swing.JFrame implements Observer {
+
+    private ISearch search;
+    private HashMap<String, Integer> tags;
+    private HashMap<Integer, TagValue> dimFields;
+    private ArrayList<String> listAvaliable;
+    private ExportDataSupport eds;
+
+    private String query;
+    private boolean keywords;
+    private boolean local;
+    private boolean network;
+    private HashMap<String, Boolean> origins;
+    
+    /** Creates new form ExportData */
+    public ExportData(String query, boolean keywords, HashMap<String, Boolean> origins) {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+        
+        jLabelExporting.setVisible(false);
+
+        try {
+            this.search = UserRefs.getInstance().getSearch();
+            
+            tags = search.getTagList();
+            dimFields = search.getDIMFields();
+
+            this.query = query;
+            this.keywords = keywords;
+            this.origins = origins;
+            
+            fillLists();
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(ExportData.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    
+    
+     public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabelExporting = new javax.swing.JLabel();
+        jTabbedPaneExport = new javax.swing.JTabbedPane();
+        jPanelBasic = new javax.swing.JPanel();
+        jButtonDown = new javax.swing.JButton();
+        jButtonUp = new javax.swing.JButton();
+        jTextFieldAvaliableFilter = new javax.swing.JTextField();
+        jLabel3 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel1 = new javax.swing.JLabel();
+        jButtonRemove = new javax.swing.JButton();
+        jButtonAdd = new javax.swing.JButton();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jListExportTags = new javax.swing.JList();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jListAvaliableTags = new javax.swing.JList();
+        jPanel2 = new javax.swing.JPanel();
+        jScrollPane3 = new javax.swing.JScrollPane();
+        jTextAreaTagList = new javax.swing.JTextArea();
+        jLabel4 = new javax.swing.JLabel();
+        jButtonExport = new javax.swing.JButton();
+        jButtonCancel = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        setTitle("Export Query Results");
+        setMinimumSize(new java.awt.Dimension(679, 387));
+
+        jLabelExporting.setIcon(new ImageIcon(getImage("ajax-loader.gif")));
+        jLabelExporting.setText("Exporting...");
+
+        jButtonDown.setText("Down");
+        jButtonDown.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonDownActionPerformed(evt);
+            }
+        });
+
+        jButtonUp.setText("Up");
+        jButtonUp.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonUpActionPerformed(evt);
+            }
+        });
+
+        jTextFieldAvaliableFilter.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyReleased(java.awt.event.KeyEvent evt) {
+                jTextFieldAvaliableFilterKeyReleased(evt);
+            }
+        });
+
+        jLabel3.setText("Tags for export:");
+
+        jLabel2.setText("Avaliable Tags:");
+
+        jLabel1.setText("Select Tags to use for export:");
+
+        jButtonRemove.setText("<-");
+        jButtonRemove.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonRemoveActionPerformed(evt);
+            }
+        });
+
+        jButtonAdd.setText("->");
+        jButtonAdd.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonAddActionPerformed(evt);
+            }
+        });
+
+        jListExportTags.setSize(new java.awt.Dimension(39, 136));
+        jScrollPane2.setViewportView(jListExportTags);
+
+        jScrollPane1.setViewportView(jListAvaliableTags);
+
+        org.jdesktop.layout.GroupLayout jPanelBasicLayout = new org.jdesktop.layout.GroupLayout(jPanelBasic);
+        jPanelBasic.setLayout(jPanelBasicLayout);
+        jPanelBasicLayout.setHorizontalGroup(
+            jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(0, 992, Short.MAX_VALUE)
+            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanelBasicLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                        .add(org.jdesktop.layout.GroupLayout.LEADING, jPanelBasicLayout.createSequentialGroup()
+                            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                .add(jPanelBasicLayout.createSequentialGroup()
+                                    .add(jLabel2)
+                                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                                    .add(jTextFieldAvaliableFilter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE))
+                                .add(org.jdesktop.layout.GroupLayout.TRAILING, jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE))
+                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                .add(jButtonAdd, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 184, Short.MAX_VALUE)
+                                .add(jButtonRemove, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 184, Short.MAX_VALUE)
+                                .add(jButtonUp, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 184, Short.MAX_VALUE)
+                                .add(jButtonDown, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE))
+                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 376, Short.MAX_VALUE)
+                                .add(jLabel3))
+                            .add(12, 12, 12))
+                        .add(org.jdesktop.layout.GroupLayout.LEADING, jPanelBasicLayout.createSequentialGroup()
+                            .add(jLabel1)
+                            .add(749, 749, 749)))
+                    .addContainerGap()))
+        );
+        jPanelBasicLayout.setVerticalGroup(
+            jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(0, 461, Short.MAX_VALUE)
+            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                .add(jPanelBasicLayout.createSequentialGroup()
+                    .addContainerGap()
+                    .add(jLabel1)
+                    .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                        .add(org.jdesktop.layout.GroupLayout.LEADING, jPanelBasicLayout.createSequentialGroup()
+                            .add(50, 50, 50)
+                            .add(jButtonAdd)
+                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                            .add(jButtonRemove)
+                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 182, Short.MAX_VALUE)
+                            .add(jButtonUp)
+                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                            .add(jButtonDown))
+                        .add(jPanelBasicLayout.createSequentialGroup()
+                            .add(11, 11, 11)
+                            .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                                .add(org.jdesktop.layout.GroupLayout.LEADING, jPanelBasicLayout.createSequentialGroup()
+                                    .add(4, 4, 4)
+                                    .add(jLabel3)
+                                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                                    .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 301, Short.MAX_VALUE))
+                                .add(org.jdesktop.layout.GroupLayout.LEADING, jPanelBasicLayout.createSequentialGroup()
+                                    .add(jPanelBasicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                                        .add(jLabel2)
+                                        .add(jTextFieldAvaliableFilter, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                                    .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                                    .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 299, Short.MAX_VALUE)))))
+                    .add(79, 79, 79)))
+        );
+
+        jTabbedPaneExport.addTab("Basic", jPanelBasic);
+
+        jTextAreaTagList.setColumns(20);
+        jTextAreaTagList.setRows(5);
+        jScrollPane3.setViewportView(jTextAreaTagList);
+
+        jLabel4.setText("Write Tags to use for export (one per line):");
+
+        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel2Layout.createSequentialGroup()
+                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jPanel2Layout.createSequentialGroup()
+                        .add(35, 35, 35)
+                        .add(jLabel4))
+                    .add(jPanel2Layout.createSequentialGroup()
+                        .addContainerGap()
+                        .add(jScrollPane3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 860, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap(126, Short.MAX_VALUE))
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(jPanel2Layout.createSequentialGroup()
+                .add(jLabel4)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jScrollPane3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 427, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        jTabbedPaneExport.addTab("Expert", jPanel2);
+
+        jButtonExport.setText("Export Data");
+        jButtonExport.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonExportActionPerformed(evt);
+            }
+        });
+
+        jButtonCancel.setText("Cancel");
+        jButtonCancel.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonCancelActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                .add(612, 612, 612)
+                .add(jLabelExporting)
+                .add(101, 101, 101)
+                .add(jButtonExport)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jButtonCancel)
+                .add(29, 29, 29))
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jTabbedPaneExport, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 1013, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(32, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jTabbedPaneExport, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 507, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 38, Short.MAX_VALUE)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jButtonExport)
+                    .add(jButtonCancel)
+                    .add(jLabelExporting))
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCancelActionPerformed
+        this.dispose();
+    }//GEN-LAST:event_jButtonCancelActionPerformed
+
+    private void jButtonAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonAddActionPerformed
+        int index =  jListAvaliableTags.getSelectedIndex();
+
+        if (index == -1)
+            return;
+
+        // removes the selected element of the list of avaliable tags
+        DefaultListModel model = (DefaultListModel) jListAvaliableTags.getModel();
+        String tagName = (String) model.getElementAt(index);
+        listAvaliable.remove(tagName);
+        updateAvaliableList(jTextFieldAvaliableFilter.getText());
+
+        // inserts the element in the list of tags to be exported
+        model = (DefaultListModel) jListExportTags.getModel();
+        model.addElement(tagName);
+        jListExportTags.setModel(model);
+    }//GEN-LAST:event_jButtonAddActionPerformed
+
+    private void jButtonRemoveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonRemoveActionPerformed
+        int index =  jListExportTags.getSelectedIndex();
+
+        if (index == -1)
+            return;
+
+        // removes the selected element of the list of export tags
+        DefaultListModel model = (DefaultListModel) jListExportTags.getModel();
+        String tagName = (String) model.getElementAt(index);
+        model.remove(index);
+        jListExportTags.setModel(model);
+
+        // inserts the element in the list of avaliable tags
+        listAvaliable.add(tagName);
+
+        //sort the list of avaliable tags
+        Collections.sort(listAvaliable);
+
+        updateAvaliableList(jTextFieldAvaliableFilter.getText());
+    }//GEN-LAST:event_jButtonRemoveActionPerformed
+
+    private void jButtonExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonExportActionPerformed
+
+        DefaultListModel list = (DefaultListModel) jListExportTags.getModel();
+
+        //if(list.isEmpty())
+        //    return;
+
+        JFileChooser chooser = new JFileChooser();
+        chooser.setCurrentDirectory(new File("."));
+        chooser.setDialogTitle("Export File Name");
+        
+        chooser.setDialogType(JFileChooser.SAVE_DIALOG);
+        chooser.setAcceptAllFileFilterUsed(false);
+        chooser.setApproveButtonText("Save");
+
+        FileFilter fileType = new ExtensionFilter("Comma-separated values", ".csv");
+
+        chooser.setFileFilter(fileType);
+        
+        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
+            String filePath = chooser.getSelectedFile().toString();
+
+            Enumeration<String> en = (Enumeration<String>) list.elements();
+            ArrayList<String> tagList = new ArrayList<String>();
+            if (jTabbedPaneExport.getSelectedIndex()==0)
+            {
+                
+                // Basic
+                while(en.hasMoreElements())
+                    tagList.add(en.nextElement());
+            }
+            else if (jTabbedPaneExport.getSelectedIndex()==1)
+            {
+                
+                String text = jTextAreaTagList.getText();
+                String [] arr = text.split("\n");
+            
+                for (String s:arr)
+                {
+                    if (!s.isEmpty())
+                    {
+                        tagList.add(s);
+                    }
+                }
+                
+            }
+            //System.out.println("Exporting with File Path: " + filePath);
+
+            try {
+                jLabelExporting.setVisible(true);
+
+                this.eds = new ExportDataSupport(query, origins, keywords, tagList, filePath);
+                //eds.addObserver(this);
+                this.eds.InitiateExport(this);
+                jListAvaliableTags.setEnabled(false);
+                jListExportTags.setEnabled(false);
+                jButtonAdd.setEnabled(false);
+                jButtonRemove.setEnabled(false);
+                jButtonExport.setEnabled(false);
+                jButtonCancel.setEnabled(false);
+                
+            } catch (Exception ex) {
+                LoggerFactory.getLogger(ExportData.class).error(ex.getMessage(), ex);
+            }
+        }
+    }//GEN-LAST:event_jButtonExportActionPerformed
+
+    private void jTextFieldAvaliableFilterKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextFieldAvaliableFilterKeyReleased
+        updateAvaliableList(jTextFieldAvaliableFilter.getText());
+    }//GEN-LAST:event_jTextFieldAvaliableFilterKeyReleased
+
+    private void jButtonUpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonUpActionPerformed
+        int index =  jListExportTags.getSelectedIndex();
+
+        if(index > 0){
+            DefaultListModel model = (DefaultListModel) jListExportTags.getModel();
+            Object element1 = model.getElementAt(index-1);
+            Object element2 = model.getElementAt(index);
+
+            model.set(index, element1);
+            model.set(index-1, element2);
+
+            jListExportTags.setModel(model);
+            jListExportTags.setSelectedIndex(index-1);
+        }
+    }//GEN-LAST:event_jButtonUpActionPerformed
+
+    private void jButtonDownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDownActionPerformed
+        int index =  jListExportTags.getSelectedIndex();
+        DefaultListModel model = (DefaultListModel) jListExportTags.getModel();
+
+        if(index > -1 && index < model.size()){
+
+            Object element1 = model.getElementAt(index);
+            Object element2 = model.getElementAt(index+1);
+
+            model.set(index+1, element1);
+            model.set(index, element2);
+
+            jListExportTags.setModel(model);
+            jListExportTags.setSelectedIndex(index+1);
+        }
+    }//GEN-LAST:event_jButtonDownActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonAdd;
+    private javax.swing.JButton jButtonCancel;
+    private javax.swing.JButton jButtonDown;
+    private javax.swing.JButton jButtonExport;
+    private javax.swing.JButton jButtonRemove;
+    private javax.swing.JButton jButtonUp;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabelExporting;
+    private javax.swing.JList jListAvaliableTags;
+    private javax.swing.JList jListExportTags;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JPanel jPanelBasic;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JScrollPane jScrollPane3;
+    private javax.swing.JTabbedPane jTabbedPaneExport;
+    private javax.swing.JTextArea jTextAreaTagList;
+    private javax.swing.JTextField jTextFieldAvaliableFilter;
+    // End of variables declaration//GEN-END:variables
+
+
+    /**
+     * Fill the list of avaliable tags and the default list of export tags with DIM Fields
+     */
+    private void fillLists(){
+        DefaultListModel listModel = new DefaultListModel();
+
+        ArrayList<TagValue> list = new ArrayList<TagValue>( dimFields.values());
+        ArrayList<String> listDIM = new ArrayList<String>();
+        
+        for(TagValue tag : list)
+            listDIM.add(tag.getAlias());
+
+        Collections.sort(listDIM);
+
+        for(String tag : listDIM)
+            listModel.addElement(tag);
+
+        jListExportTags.setModel(listModel);
+
+
+        ArrayList<String> listTags = new ArrayList<String>(tags.keySet());
+        listAvaliable = new ArrayList<String>();
+
+        for(String tag: listTags)
+            if(!listDIM.contains(tag))
+                listAvaliable.add(tag);
+
+        listAvaliable.add("FileName");
+        listAvaliable.add("FilePath");
+
+        //sort the list of avaliable tags
+        Collections.sort(listAvaliable);
+
+        updateAvaliableList(null);
+    }
+
+    @Override
+    public void update(Observable o, Object arg) {
+        if (o==null)
+        {
+            LoggerFactory.getLogger(ExportData.class).error("Update invoked with null o");
+            return;
+        }
+        LoggerFactory.getLogger(ExportData.class).debug("Update");
+        Boolean finish = (Boolean) arg;
+        
+        class AuxThread extends Thread
+        {
+            private javax.swing.JFrame t;
+            public void set(javax.swing.JFrame t)
+            {
+                this.t = t;
+            }
+            
+            @Override
+            public void run() 
+            {
+                
+                JOptionPane.showMessageDialog(t, "Query results successfully exported!", "Export Query Results", JOptionPane.INFORMATION_MESSAGE);
+                t.dispose();
+            }
+        };
+        
+        if (finish)
+        {
+            AuxThread _thread = new AuxThread();
+            _thread.set(this);
+            _thread.start();
+            
+            this.setVisible(false);
+        }
+    }
+
+    /**
+     * Update the avaliable tags jList based on a String prefix to filter tags
+     * If you don't want to filter anything, send the prefix NULL or "" (empty string)
+     *
+     * @param prefix - string with the start of tag name to filter
+     */
+    private void updateAvaliableList(String prefix){
+        DefaultListModel listModel = new DefaultListModel();
+
+        for(String tag: listAvaliable){
+            if(prefix != null && !prefix.equals("")){
+                if(tag.toLowerCase().startsWith(prefix.toLowerCase()))
+                    listModel.addElement(tag);
+            }
+            else
+                listModel.addElement(tag);
+        }
+
+        jListAvaliableTags.setModel(listModel);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.form
new file mode 100755
index 0000000..a6d05a0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.form
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="0"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jScrollPane1" pref="387" max="32767" attributes="0"/>
+                      <EmptySpace min="9" pref="9" max="9" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jCheckBoxApplyAll" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="138" max="32767" attributes="0"/>
+                      <Component id="jButtonYes" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonNo" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabelNumber" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jScrollPane1" pref="149" max="32767" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelNumber" alignment="0" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jCheckBoxApplyAll" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonNo" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonYes" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="The files listed bellow are already indexed:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Do you want to index them again?"/>
+      </Properties>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListIndexedFiles">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonYes">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Yes"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonYesActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonNo">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="No"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonNoActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JCheckBox" name="jCheckBoxApplyAll">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="apply to all"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelNumber">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="#####"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Number of files:"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.java
new file mode 100755
index 0000000..196332d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/FileAlreadyIndexed.java
@@ -0,0 +1,313 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPendingMessages;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class FileAlreadyIndexed extends javax.swing.JFrame {
+
+    private static IPendingMessages pendingMessages;
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static FileAlreadyIndexed instance;
+
+    public static FileAlreadyIndexed getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new FileAlreadyIndexed();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(FileAlreadyIndexed.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    /** Creates new form FileAlreadyIndexed */
+    private FileAlreadyIndexed() {
+        initComponents();
+
+        this.setTitle("Re-Index Files");
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        jLabelNumber.setText("0");
+        
+        jListIndexedFiles.setModel(new DefaultListModel());
+
+        pendingMessages = AdminRefs.getInstance().getPendingMessages();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jListIndexedFiles = new javax.swing.JList();
+        jButtonYes = new javax.swing.JButton();
+        jButtonNo = new javax.swing.JButton();
+        jCheckBoxApplyAll = new javax.swing.JCheckBox();
+        jLabelNumber = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        jLabel1.setText("The files listed bellow are already indexed:");
+
+        jLabel2.setText("Do you want to index them again?");
+
+        jScrollPane1.setViewportView(jListIndexedFiles);
+
+        jButtonYes.setText("Yes");
+        jButtonYes.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonYesActionPerformed(evt);
+            }
+        });
+
+        jButtonNo.setText("No");
+        jButtonNo.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonNoActionPerformed(evt);
+            }
+        });
+
+        jCheckBoxApplyAll.setText("apply to all");
+
+        jLabelNumber.setText("#####");
+
+        jLabel3.setText("Number of files:");
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jLabel1)
+                    .add(layout.createSequentialGroup()
+                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 387, Short.MAX_VALUE)
+                        .add(9, 9, 9))
+                    .add(layout.createSequentialGroup()
+                        .add(jCheckBoxApplyAll)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 138, Short.MAX_VALUE)
+                        .add(jButtonYes)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonNo))
+                    .add(jLabel2)
+                    .add(layout.createSequentialGroup()
+                        .add(jLabel3)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jLabelNumber)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(jLabel1)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jLabel3)
+                    .add(jLabelNumber))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(jLabel2)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jCheckBoxApplyAll)
+                    .add(jButtonNo)
+                    .add(jButtonYes))
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonNoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonNoActionPerformed
+        DefaultListModel model = (DefaultListModel) jListIndexedFiles.getModel();
+
+        if(jCheckBoxApplyAll.isSelected()){
+             model.clear();
+            
+            jLabelNumber.setText("0");
+            this.setVisible(false);
+        }
+        else{
+            int[] indices = jListIndexedFiles.getSelectedIndices();
+
+            if(indices.length > 0){
+
+                for (int i = 0; i < indices.length; i++)
+                    model.remove(indices[i]);
+
+                //jListIndexedFiles.setModel(model);
+                jLabelNumber.setText(String.valueOf(Integer.valueOf(jLabelNumber.getText()) - indices.length));
+
+                if(model.isEmpty())
+                    this.setVisible(false);
+            }
+            else
+                JOptionPane.showMessageDialog(this, "You need to select some files.", "Select Files", JOptionPane.ERROR_MESSAGE);
+        }
+    }//GEN-LAST:event_jButtonNoActionPerformed
+
+    private void jButtonYesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonYesActionPerformed
+       boolean showTaskList = true;
+
+        DefaultListModel model = (DefaultListModel) jListIndexedFiles.getModel();
+        ArrayList<String> list = new ArrayList<String>();
+
+        if(jCheckBoxApplyAll.isSelected()){
+            Enumeration<String> en = (Enumeration<String>) model.elements();
+
+            while(en.hasMoreElements())
+                list.add(en.nextElement());
+
+            if(list.size() > 0)
+                AdminRefs.getInstance().reIndex(list);
+
+            model.clear();
+            
+            jLabelNumber.setText("0");
+            this.setVisible(false);
+        }
+        else{
+            int[] indices = jListIndexedFiles.getSelectedIndices();
+
+            if(indices.length > 0){
+
+                for (int i = 0; i < indices.length; i++){
+                    list.add((String) model.get(indices[i]));
+                    model.remove(indices[i]);
+                }
+
+                AdminRefs.getInstance().reIndex(list);
+                //jListIndexedFiles.setModel(model);
+                jLabelNumber.setText(String.valueOf(Integer.valueOf(jLabelNumber.getText()) - indices.length));
+
+                if(model.isEmpty())
+                    this.setVisible(false);
+            }
+            else{
+                JOptionPane.showMessageDialog(this, "You need to select some files.", "Select Files", JOptionPane.ERROR_MESSAGE);
+                showTaskList = false;
+            }
+        }
+
+        /*if (showTaskList)
+        {
+            TaskList tasks = TaskList.getInstance();
+            tasks.setVisible(true);
+            tasks.toFront();
+        }*/
+    }//GEN-LAST:event_jButtonYesActionPerformed
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        //if the user closes the window, none of the files will be reIndexed
+
+        jCheckBoxApplyAll.setSelected(true);
+        jButtonNo.doClick();
+    }//GEN-LAST:event_formWindowClosing
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonNo;
+    private javax.swing.JButton jButtonYes;
+    private javax.swing.JCheckBox jCheckBoxApplyAll;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabelNumber;
+    private javax.swing.JList jListIndexedFiles;
+    private javax.swing.JScrollPane jScrollPane1;
+    // End of variables declaration//GEN-END:variables
+
+
+    /**
+     * Adds all the indexed files that can be re-indexed
+     *
+     * @param list of already indexed files
+     */
+    private synchronized void addAlreadyIndexedFiles(ArrayList<String> list){
+        DefaultListModel model = (DefaultListModel) jListIndexedFiles.getModel();
+
+        for(String filePath: list)
+            model.addElement(filePath);
+
+        //jListIndexedFiles.setModel(model);
+        jListIndexedFiles.revalidate();
+        this.repaint();
+        jLabelNumber.setText(String.valueOf(Integer.valueOf(jLabelNumber.getText()) + list.size()));
+    }
+
+    /**
+     * Get the list of already indexed files that can be re-indexed
+     *
+     * This list is accessible from the remote object PendingMessages, located on the server
+     */
+    public void getList(){
+        try {
+            ArrayList<String> list = pendingMessages.getFilesAlreadyIndexed();
+
+            if(list != null && list.size() > 0){
+                addAlreadyIndexedFiles(list);
+
+                if (this.isVisible() == false)
+                    this.setVisible(true);
+            }
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(FileAlreadyIndexed.class).error(ex.getMessage(), ex);
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.form
new file mode 100755
index 0000000..a02f51a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.form
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.7" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="name" type="java.lang.String" value="Meta-data fields" noResource="true"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-75,0,0,1,87"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+    <Property name="axis" type="int" value="1"/>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+      <Properties>
+        <Property name="orientation" type="int" value="0"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Properties>
+            <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+              <Font name="Lucida Grande" size="18" style="1"/>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="top"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabelTitle">
+              <Properties>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Grande" size="18" style="1"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="jLabelTitle"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="right"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+              <AuxValues>
+                <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+              </AuxValues>
+
+              <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+              <SubComponents>
+                <Component class="javax.swing.JTable" name="jTableMetaData">
+                  <Properties>
+                    <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                      <Connection code="model" type="code"/>
+                    </Property>
+                  </Properties>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JTable(model)"/>
+                    <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="model = new MetaDataModel();"/>
+                  </AuxValues>
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.java
new file mode 100755
index 0000000..c1a6fe7
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/IndexedMetaData.java
@@ -0,0 +1,337 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * IndexedMetaData.java
+ *
+ * Created on Feb 19, 2010, 6:39:59 PM
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.rmi.RemoteException;
+import org.slf4j.LoggerFactory;
+import java.awt.Dimension;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.TransferHandler;
+import javax.swing.table.AbstractTableModel;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public class IndexedMetaData extends javax.swing.JFrame
+{
+
+    /*********************
+     * Private attributes
+     *********************/
+     private SearchResult searchResult ;
+     private MainWindow main ;
+
+     private MetaDataModel model;
+
+
+    /** Creates new form IndexedMetaData */
+    public IndexedMetaData(SearchResult searchResult, MainWindow main)
+    {
+        this.main = main;
+        this.searchResult = searchResult;
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+        
+        // Get the size of the screen
+        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
+        
+        // Determine the new location of the window
+        int w = this.getSize().width;
+        int h = this.getSize().height;
+        int x = (dim.width - w) / 2;
+        int y = (dim.height - h) / 2;
+
+        // Move the window
+        this.setLocation(x, y);
+
+        String PatientName = (String) searchResult.getExtraData().get("PatientName");
+
+        this.setTitle(PatientName + " - " + searchResult.getURI());
+        fill();
+        
+    }
+
+
+
+
+    /***************************
+     * Private Methods
+     ***************************/
+
+
+
+
+    private void fill()
+    {
+
+        TransferHandler th = jTableMetaData.getTransferHandler();
+        if (th != null) {
+            Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
+            th.exportToClipboard(jTableMetaData, cb, TransferHandler.COPY);
+        }
+
+        fillTitle();
+    }
+
+    private void fillTitle()
+    {
+        jLabelTitle.setText(searchResult.getURI().toString());
+    }
+    
+    /***************************
+     * Private Classes
+     ***************************/
+    
+    class MetaData implements Comparable
+    {
+        private String name  = "" ;
+        private String value = "" ;
+
+        public MetaData(String name, String value )
+        {
+            this.name = name ;
+            this.value = value ;
+        }
+
+        /**
+         * @return the value
+         */
+        public String getValue()
+        {
+            return value;
+        }
+
+        /**
+         * @param value the value to set
+         */
+        public void setValue(String value)
+        {
+            this.value = value;
+        }
+
+
+        /**
+         * @return the name
+         */
+        public String getName()
+        {
+            return name;
+        }
+
+        /**
+         * @param name the name to set
+         */
+        public void setName(String name)
+        {
+            this.name = name;
+        }
+
+        
+
+        @Override
+        public int compareTo(Object o)
+        {
+
+            MetaData meta = (MetaData) o;
+            return this.name.compareTo(meta.getName());
+
+        }
+
+        
+
+    }
+
+
+    class MetaDataModel extends AbstractTableModel
+    {
+
+        static final int NAME = 0 ;
+        static final int VALUE = 1 ;
+
+        private String[] headers = { "Name", "Value", };
+        private ArrayList<MetaData> metaData = new ArrayList<MetaData>();
+
+        public MetaDataModel()
+        {            
+            try {
+                HashMap resultFields = searchResult.getExtraData();
+
+                List resultList = UserRefs.getInstance().getSearch().SearchIndexedMetaData(searchResult);
+                
+
+                if (resultList.size() > 0) {
+                    //DebugManager.getInstance().debug("Found results (In Meta)");
+                    
+                    SearchResult r = (SearchResult) resultList.get(0);
+                    resultFields = r.getExtraData();
+                }
+
+                Iterator it = resultFields.keySet().iterator();
+                while (it.hasNext()) {
+                    String key = (String) it.next();
+                    metaData.add(new MetaData(key, (String) resultFields.get(key)));
+                }
+                
+                Collections.sort(metaData);
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(IndexedMetaData.class).error(ex.getMessage(), ex);
+            }
+        }
+
+        public String getColumnName(int c)
+        {
+            return headers[c];
+        }
+
+
+        @Override
+        public int getRowCount()
+        {
+            return metaData.size();
+        }
+
+        @Override
+        public int getColumnCount()
+        {
+            return headers.length ;
+        }
+
+        @Override
+        public Object getValueAt(int rowIndex, int columnIndex)
+        {
+            String result = "";
+            MetaData m = this.metaData.get(rowIndex);
+            if (columnIndex==NAME)
+            {
+                result = m.getName();
+            }
+            else if (columnIndex==VALUE)
+            {
+                result = m.getValue();
+            }
+            else
+            {
+                boolean cond = (columnIndex!=NAME||columnIndex!=VALUE);
+                assert cond ;
+            }
+            
+            return result ;
+
+        }
+
+
+        
+    }
+
+
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jPanel1 = new javax.swing.JPanel();
+        jLabelTitle = new javax.swing.JLabel();
+        jPanel2 = new javax.swing.JPanel();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        model = new MetaDataModel();
+        jTableMetaData = new javax.swing.JTable(model);
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setName("Meta-data fields"); // NOI18N
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+        getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
+
+        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
+
+        jPanel1.setFont(new java.awt.Font("Lucida Grande", 1, 18));
+        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.LINE_AXIS));
+
+        jLabelTitle.setFont(new java.awt.Font("Lucida Grande", 1, 18));
+        jLabelTitle.setText("jLabelTitle");
+        jPanel1.add(jLabelTitle);
+
+        jSplitPane1.setTopComponent(jPanel1);
+
+        jPanel2.setLayout(new javax.swing.BoxLayout(jPanel2, javax.swing.BoxLayout.LINE_AXIS));
+
+        jTableMetaData.setModel(model);
+        jScrollPane1.setViewportView(jTableMetaData);
+
+        jPanel2.add(jScrollPane1);
+
+        jSplitPane1.setRightComponent(jPanel2);
+
+        getContentPane().add(jSplitPane1);
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        this.setVisible(false);
+
+        main.setEnabled(true);
+        main.toFront();
+
+    }//GEN-LAST:event_formWindowClosing
+
+    
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JLabel jLabelTitle;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JTable jTableMetaData;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.form
new file mode 100755
index 0000000..1a0586b
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.form
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Logs"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[400, 300]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jTabbedPane1" pref="511" max="32767" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
+                      <Component id="jButtonClear" min="-2" max="-2" attributes="1"/>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <Component id="jButtonClear" min="-2" pref="64" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="jTabbedPane1" pref="276" max="32767" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+      <AccessibilityProperties>
+        <Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Server Log"/>
+      </AccessibilityProperties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Server Log">
+                <Property name="tabTitle" type="java.lang.String" value="Server Log"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="jTextLogWindow">
+              <Properties>
+                <Property name="columns" type="int" value="20"/>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="rows" type="int" value="5"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane8">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="DICOM Log Services">
+                <Property name="tabTitle" type="java.lang.String" value="DICOM Log Services"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTree" name="jTreeLog">
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTree(topLog)"/>
+                <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="//Create the nodes. &#xa;topLog =new DefaultMutableTreeNode("Logging..");"/>
+              </AuxValues>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="User Sessions Log">
+                <Property name="tabTitle" type="java.lang.String" value="User Sessions Log"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="jTextSessionsLogWindow">
+              <Properties>
+                <Property name="columns" type="int" value="20"/>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="rows" type="int" value="5"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonClear">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("log.gif"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Clear Log"/>
+        <Property name="horizontalTextPosition" type="int" value="0"/>
+        <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[97, 21]"/>
+        </Property>
+        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[97, 21]"/>
+        </Property>
+        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[97, 21]"/>
+        </Property>
+        <Property name="verticalTextPosition" type="int" value="3"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonClearActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.java
new file mode 100755
index 0000000..70fda64
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Logs.java
@@ -0,0 +1,280 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.rmi.server.RMISocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.ImageIcon;
+
+import javax.swing.JTree;
+import javax.swing.JFrame;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import pt.ua.dicoogle.rGUI.client.signals.LogsSignal;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ILogs;
+import pt.ua.dicoogle.Main;
+
+import pt.ua.dicoogle.DicomLog.LogLine;
+import pt.ua.dicoogle.rGUI.MultihomeRMIClientSocketFactory;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ILogsSignal;
+
+/**
+ * There are two diferent logs in this class
+ * the Server Log with the activities in server
+ * and the DICOM Services Log
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class Logs extends JFrame {
+
+    private static Logs instance = null;
+    private static ILogs logs;
+    private static ILogsSignal logsSignal;
+    private DefaultMutableTreeNode topLog = null;
+    
+     public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+
+
+    public static synchronized Logs getInstance() {
+        if (instance == null) {
+            instance = new Logs();
+        }
+
+        return instance;
+    }
+
+    /** Creates new form Logs */
+    private Logs() {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+
+        Logs.logs = AdminRefs.getInstance().getLogs();
+
+        topLog = new DefaultMutableTreeNode("Logging..");
+        jTreeLog.setModel(new DefaultTreeModel(topLog));
+
+        try {
+            logsSignal = new LogsSignal(this);
+            
+            ILogsSignal logsSignalStub = (ILogsSignal) UnicastRemoteObject.exportObject(logsSignal, 0, new MultihomeRMIClientSocketFactory(), RMISocketFactory.getDefaultSocketFactory());;
+            
+            //if (logs == null)
+            //    System.out.println("LOGS IS NULL");
+
+            logs.RegisterSignalBack(logsSignalStub);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void getDICOMLog() {
+        try {
+            ArrayList<LogLine> logLines = logs.getPendingDICOMLog();
+
+            for (LogLine line : logLines) {
+                addDICOMLog(line);
+            }
+
+            jTreeLog.setModel(new DefaultTreeModel(topLog));
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void getServerLog() {
+        try {
+            String logText = logs.getServerLog();
+
+            jTextLogWindow.setText(logText);
+            jTextLogWindow.setCaretPosition(jTextLogWindow.getDocument().getLength());
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void getSessionsLog(){
+        try {
+            String addLog = logs.getPendingSessionsLog();
+            
+            jTextSessionsLogWindow.setText(jTextSessionsLogWindow.getText() + addLog);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    private void addDICOMLog(LogLine l) {
+        DefaultMutableTreeNode group = null;
+        DefaultMutableTreeNode subGroup = null;
+
+        group = new DefaultMutableTreeNode(l.getType() + " -- " + l.getDate());
+        topLog.add(group);
+        subGroup = new DefaultMutableTreeNode(l.getAe() + ":: " + l.getAdd());
+        group.add(subGroup);
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jTabbedPane1 = new javax.swing.JTabbedPane();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTextLogWindow = new javax.swing.JTextArea();
+        jScrollPane8 = new javax.swing.JScrollPane();
+        //Create the nodes.
+        topLog =new DefaultMutableTreeNode("Logging..");
+        jTreeLog = new JTree(topLog);
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jTextSessionsLogWindow = new javax.swing.JTextArea();
+        jButtonClear = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Logs");
+        setMinimumSize(new java.awt.Dimension(400, 300));
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        jTextLogWindow.setColumns(20);
+        jTextLogWindow.setEditable(false);
+        jTextLogWindow.setRows(5);
+        jScrollPane1.setViewportView(jTextLogWindow);
+
+        jTabbedPane1.addTab("Server Log", jScrollPane1);
+
+        jScrollPane8.setViewportView(jTreeLog);
+
+        jTabbedPane1.addTab("DICOM Log Services", jScrollPane8);
+
+        jTextSessionsLogWindow.setColumns(20);
+        jTextSessionsLogWindow.setEditable(false);
+        jTextSessionsLogWindow.setRows(5);
+        jScrollPane2.setViewportView(jTextSessionsLogWindow);
+
+        jTabbedPane1.addTab("User Sessions Log", jScrollPane2);
+
+        jButtonClear.setIcon(new ImageIcon(getImage("log.gif")));
+        jButtonClear.setText("Clear Log");
+        jButtonClear.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonClear.setMaximumSize(new java.awt.Dimension(97, 21));
+        jButtonClear.setMinimumSize(new java.awt.Dimension(97, 21));
+        jButtonClear.setPreferredSize(new java.awt.Dimension(97, 21));
+        jButtonClear.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonClear.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonClearActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 511, Short.MAX_VALUE))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(14, 14, 14)
+                        .addComponent(jButtonClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addComponent(jButtonClear, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        jTabbedPane1.getAccessibleContext().setAccessibleName("Server Log");
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        MainWindow main = MainWindow.getInstance();
+
+        main.toFront();
+        main.setEnabled(true);
+
+        this.dispose();
+    }//GEN-LAST:event_formWindowClosing
+
+    private void jButtonClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonClearActionPerformed
+        try {
+            if (jTabbedPane1.getSelectedIndex() == 0) {
+                logs.clearServerLog();
+            } else if(jTabbedPane1.getSelectedIndex() == 1) {
+
+                //LogDICOM.getInstance().clearLog();
+                logs.clearDICOMLog();
+
+                topLog = new DefaultMutableTreeNode("Logging..");
+
+                jTreeLog.setModel(new DefaultTreeModel(topLog));
+            }
+            else {
+                jTextSessionsLogWindow.setText("");
+                logs.clearSessionsLog();
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+}//GEN-LAST:event_jButtonClearActionPerformed
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonClear;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JScrollPane jScrollPane8;
+    private javax.swing.JTabbedPane jTabbedPane1;
+    private javax.swing.JTextArea jTextLogWindow;
+    private javax.swing.JTextArea jTextSessionsLogWindow;
+    private javax.swing.JTree jTreeLog;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.form
new file mode 100755
index 0000000..6b069d1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.form
@@ -0,0 +1,1436 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.7" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Menu class="javax.swing.JMenuBar" name="jMenuBar3">
+      <SubComponents>
+        <Menu class="javax.swing.JMenu" name="jMenu9">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="File"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemChangePassword">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Change Password"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemChangePasswordActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuDirScan2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Scan Disk"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuDirScanActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuDirScanResume">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Scan Disk (resume)"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuDirScanResumeActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemShutdown">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Shutdown Client&Server"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemShutdownActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem11">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Exit Client"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem11ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem7">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Exit Client&Server"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem7ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu10">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Edit"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemPreferences">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Preferences"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem2ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemServices">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Services"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemServicesActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem10">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Logs"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem10ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemUsers">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="User Accounts"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemUsersActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemActiveUsers">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="ActiveUsers"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemActiveUsersActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenuTools2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Tools"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItemDcm2jpeg2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="dcm2jpeg"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItemDcm2jpeg2ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu11">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Skin"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Business"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem1ActionPerformed1"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Business Blue Steel"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem2ActionPerformed1"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem3">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Business Black Steel"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem3ActionPerformed1"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem4">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Creme"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem4ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem5">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Magma"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem5ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem6">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Raven"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem6ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem8">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Raven Graphite Glass"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem8ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="pluginMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Plugins"/>
+          </Properties>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu12">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Help"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem9">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="About"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem3ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+      </SubComponents>
+    </Menu>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="0"/>
+    <Property name="title" type="java.lang.String" value="Dicoogle PACS Archive"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[700, 526]"/>
+    </Property>
+    <Property name="name" type="java.lang.String" value="MainWindow" noResource="true"/>
+  </Properties>
+  <AccessibilityProperties>
+    <Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Dicoogle PACS Archive"/>
+  </AccessibilityProperties>
+  <SyntheticProperties>
+    <SyntheticProperty name="menuBar" type="java.lang.String" value="jMenuBar3"/>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowOpened" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowOpened"/>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+    <EventHandler event="windowIconified" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowIconified"/>
+    <EventHandler event="windowDeiconified" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowDeiconified"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,3,78,0,0,5,7"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="tabPanel">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="Center"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane2">
+          <Properties>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[602, 602]"/>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Search">
+                <Property name="tabTitle" type="java.lang.String" value="Search"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Container class="javax.swing.JPanel" name="jPanel5">
+              <Properties>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[1197, 100]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[1197, 100]"/>
+                </Property>
+              </Properties>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jSeparator2" alignment="0" pref="1279" max="32767" attributes="1"/>
+                      <Component id="jSeparator1" alignment="0" pref="1279" max="32767" attributes="0"/>
+                      <Group type="102" alignment="1" attributes="0">
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                  <Component id="SelectDefaultSearch" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="SelectAdvancedSearch" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
+                                  <Component id="jPanel6" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="1" attributes="0">
+                                  <Component id="jScrollPane1" pref="846" max="32767" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jPanel9" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Component id="jPanel2" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jPanel1" alignment="1" max="32767" attributes="1"/>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                                  <Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  <Component id="SelectDefaultSearch" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  <Component id="SelectAdvancedSearch" alignment="3" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Component id="jPanel6" min="-2" max="-2" attributes="1"/>
+                          </Group>
+                          <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
+                          <Component id="jSeparator2" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="jPanel2" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
+                          <Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="jPanel9" max="32767" attributes="1"/>
+                              <Component id="jScrollPane1" alignment="0" pref="0" max="32767" attributes="3"/>
+                          </Group>
+                      </Group>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+              <SubComponents>
+                <Component class="javax.swing.JRadioButton" name="SelectAdvancedSearch">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Advanced search"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="SelectAdvancedSearchActionPerformed"/>
+                  </Events>
+                </Component>
+                <Component class="javax.swing.JRadioButton" name="SelectDefaultSearch">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Default search"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="SelectDefaultSearchActionPerformed"/>
+                  </Events>
+                </Component>
+                <Component class="javax.swing.JLabel" name="jLabel5">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Search type:"/>
+                  </Properties>
+                </Component>
+                <Container class="javax.swing.JPanel" name="jPanel2">
+
+                  <Layout>
+                    <DimensionLayout dim="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Group type="103" groupAlignment="0" attributes="0">
+                                          <Component id="jLabel8" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          <Component id="jLabel9" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          <Component id="jLabel10" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          <Component id="jLabel11" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                                          <Component id="PatientID" alignment="0" max="32767" attributes="1"/>
+                                          <Component id="PatientGender" alignment="0" pref="118" max="32767" attributes="1"/>
+                                          <Component id="Physician" alignment="0" max="32767" attributes="1"/>
+                                          <Component id="InstitutionName" alignment="0" max="32767" attributes="1"/>
+                                          <Component id="PatientName" alignment="0" max="32767" attributes="1"/>
+                                          <Component id="OperatorName" alignment="0" max="32767" attributes="1"/>
+                                      </Group>
+                                  </Group>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Component id="AdvancedSearchButton" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="ResetFields" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <Component id="jLabel19" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel7" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel20" alignment="0" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="jPanel3" min="-2" max="-2" attributes="1"/>
+                                  <Component id="jPanel4" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <EmptySpace pref="381" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                    <DimensionLayout dim="1">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Group type="102" attributes="0">
+                                      <EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="AdvancedSearchButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="ResetFields" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="jLabel19" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="PatientName" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel20" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="PatientID" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel8" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="PatientGender" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel9" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="InstitutionName" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel10" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="Physician" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="3" attributes="0">
+                                          <Component id="jLabel11" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="OperatorName" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="jPanel3" min="-2" pref="96" max="-2" attributes="0"/>
+                                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                      <Component id="jPanel4" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                              </Group>
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JLabel" name="jLabel7">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Patient Name:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel8">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Patient Gender:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel9">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Institution Name:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel10">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Physician:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel11">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Operator Name:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="OperatorName">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="(All operators)"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="Physician">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="(All physicians)"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JComboBox" name="PatientGender">
+                      <Properties>
+                        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                          <Connection code="new javax.swing.DefaultComboBoxModel(new String[] { "All", "Male", "Female" })" type="code"/>
+                        </Property>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="PatientName">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="(All patients)"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="InstitutionName">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="(All institutions)"/>
+                      </Properties>
+                    </Component>
+                    <Container class="javax.swing.JPanel" name="jPanel3">
+
+                      <Layout>
+                        <DimensionLayout dim="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="1" attributes="0">
+                                  <EmptySpace max="32767" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="jLabel14" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                          <Component id="ModalSelectAll" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="ModalSelectNone" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="1" attributes="0">
+                                              <Group type="103" groupAlignment="0" attributes="0">
+                                                  <Component id="ModalDX" alignment="0" min="-2" max="-2" attributes="0"/>
+                                                  <Component id="ModalCT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              </Group>
+                                              <Component id="ModalCR" alignment="1" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Component id="ModalMG" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalNM" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalMR" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                          <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Component id="ModalPT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalSC" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalRF" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                          <EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Component id="ModalUS" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalXA" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Component id="ModalOT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="ModalES" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                                  <EmptySpace min="-2" pref="202" max="-2" attributes="0"/>
+                              </Group>
+                          </Group>
+                        </DimensionLayout>
+                        <DimensionLayout dim="1">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Group type="103" groupAlignment="3" attributes="0">
+                                      <Component id="jLabel14" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalSelectAll" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalSelectNone" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="ModalPT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                                          <Component id="ModalMG" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          <Component id="ModalCR" alignment="3" min="-2" pref="18" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Component id="ModalXA" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalES" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="ModalUS" alignment="0" min="-2" pref="23" max="-2" attributes="0"/>
+                                      <Component id="ModalRF" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalMR" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalCT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="ModalOT" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalSC" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalNM" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="ModalDX" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="32767" attributes="0"/>
+                              </Group>
+                          </Group>
+                        </DimensionLayout>
+                      </Layout>
+                      <SubComponents>
+                        <Component class="javax.swing.JCheckBox" name="ModalCR">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="CR"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalCRActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalMG">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="MG"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalMGActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalPT">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="PT"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalPTActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalCT">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="CT"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalCTActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalMR">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="MR"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalMRActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalRF">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="RF"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalRFActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalDX">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="DX"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalDXActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalNM">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="NM"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalNMActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalSC">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="SC"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalSCActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalES">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="ES"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalESActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalOT">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="OT"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalOTActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalUS">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="US"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalUSActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="ModalXA">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="XA"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalXAActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel14">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Modality:"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JRadioButton" name="ModalSelectAll">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Select all"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalSelectAllActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JRadioButton" name="ModalSelectNone">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Select none"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ModalSelectNoneActionPerformed"/>
+                          </Events>
+                        </Component>
+                      </SubComponents>
+                    </Container>
+                    <Component class="javax.swing.JLabel" name="jLabel19">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Note: Only what you change will modify the default query."/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel20">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Patient ID:"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="PatientID">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="(All IDs)"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="AdvancedSearchButton">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Search"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="AdvancedSearchButtonActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="ResetFields">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Reset fields"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ResetFieldsActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Container class="javax.swing.JPanel" name="jPanel4">
+
+                      <Layout>
+                        <DimensionLayout dim="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" attributes="0">
+                                  <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="ExactDate" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="DateRange" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="jLabel12" min="-2" max="-2" attributes="0"/>
+                                          <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
+                                          <Component id="StudyDate" min="-2" pref="87" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="jLabel13" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                                  <EmptySpace min="-2" pref="71" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="0" attributes="0">
+                                  <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
+                                  <Component id="jLabel15" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" attributes="0">
+                                          <Component id="StudyDateRangeInitialBoundary" min="-2" pref="92" max="-2" attributes="0"/>
+                                          <EmptySpace max="-2" attributes="0"/>
+                                          <Component id="jLabel16" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Component id="StudyDateRangeInitialBoundaryActivation" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Component id="StudyDateRangeTerminalBoundary" min="-2" pref="92" max="-2" attributes="0"/>
+                                          <EmptySpace max="32767" attributes="0"/>
+                                          <Component id="jLabel17" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <Component id="StudyDateRangeTerminalBoundaryActivation" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                              </Group>
+                          </Group>
+                        </DimensionLayout>
+                        <DimensionLayout dim="1">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Group type="103" groupAlignment="3" attributes="0">
+                                      <Component id="ExactDate" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="DateRange" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="3" attributes="0">
+                                      <Component id="StudyDate" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel13" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel12" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="3" attributes="0">
+                                              <Component id="StudyDateRangeInitialBoundaryActivation" alignment="3" min="-2" max="-2" attributes="0"/>
+                                              <Component id="StudyDateRangeTerminalBoundaryActivation" alignment="3" min="-2" max="-2" attributes="0"/>
+                                              <Component id="jLabel15" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                      </Group>
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
+                                          <Group type="103" groupAlignment="3" attributes="0">
+                                              <Component id="StudyDateRangeInitialBoundary" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
+                                              <Component id="jLabel16" alignment="3" min="-2" max="-2" attributes="0"/>
+                                              <Component id="StudyDateRangeTerminalBoundary" alignment="3" min="-2" max="-2" attributes="0"/>
+                                              <Component id="jLabel17" alignment="3" min="-2" max="-2" attributes="0"/>
+                                          </Group>
+                                      </Group>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                              </Group>
+                          </Group>
+                        </DimensionLayout>
+                      </Layout>
+                      <SubComponents>
+                        <Component class="javax.swing.JCheckBox" name="StudyDateRangeInitialBoundaryActivation">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="From:"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="StudyDateRangeInitialBoundaryActivationActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JTextField" name="StudyDateRangeInitialBoundary">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="(Beginning)"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel16">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="--"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JCheckBox" name="StudyDateRangeTerminalBoundaryActivation">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="To:"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="StudyDateRangeTerminalBoundaryActivationActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JTextField" name="StudyDateRangeTerminalBoundary">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="(Today)"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JTextField" name="StudyDate">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="(All dates)"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel13">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="(yyyymmdd form)"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel15">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Date Range:"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel12">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Date:"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel4">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Study Date search type:"/>
+                          </Properties>
+                        </Component>
+                        <Component class="javax.swing.JRadioButton" name="ExactDate">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Exact Date"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ExactDateActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JRadioButton" name="DateRange">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="Date Range"/>
+                          </Properties>
+                          <Events>
+                            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="DateRangeActionPerformed"/>
+                          </Events>
+                        </Component>
+                        <Component class="javax.swing.JLabel" name="jLabel17">
+                          <Properties>
+                            <Property name="text" type="java.lang.String" value="(yyyymmdd form)"/>
+                          </Properties>
+                        </Component>
+                      </SubComponents>
+                    </Container>
+                  </SubComponents>
+                </Container>
+                <Container class="javax.swing.JPanel" name="jPanel1">
+
+                  <Layout>
+                    <DimensionLayout dim="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Component id="jLabel1" min="-2" pref="108" max="-2" attributes="0"/>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="jTextFieldQuery" min="-2" pref="328" max="-2" attributes="0"/>
+                                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                                      <Component id="jCheckBoxKeywords" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Component id="jButtonSearch" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="SearchTips" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace max="-2" attributes="0"/>
+                                      <Component id="jButtonQueryHistory" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <EmptySpace pref="683" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                    <DimensionLayout dim="1">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                                  <Component id="jButtonSearch" alignment="0" max="32767" attributes="1"/>
+                                  <Component id="SearchTips" alignment="0" max="32767" attributes="1"/>
+                                  <Component id="jButtonQueryHistory" alignment="0" max="32767" attributes="1"/>
+                              </Group>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="3" attributes="0">
+                                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jTextFieldQuery" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jCheckBoxKeywords" alignment="3" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace pref="37" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JLabel" name="jLabel1">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Search Pattern :"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel3">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Regular expressions are supported (eg: A*)."/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JTextField" name="jTextFieldQuery">
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jTextFieldQueryActionPerformed"/>
+                        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTextFieldQueryKeyPressed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="jButtonSearch">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Search"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonSearchActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="SearchTips">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Search Tips"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="SearchTipsActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JCheckBox" name="jCheckBoxKeywords">
+                      <Properties>
+                        <Property name="selected" type="boolean" value="true"/>
+                        <Property name="text" type="java.lang.String" value="keywords"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="jButtonQueryHistory">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Query History"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonQueryHistoryActionPerformed"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Container class="javax.swing.JPanel" name="jPanel9">
+
+                  <Layout>
+                    <DimensionLayout dim="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <EmptySpace min="120" pref="120" max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="jButtonExport" alignment="1" pref="259" max="32767" attributes="0"/>
+                                  <Component id="jButtonDownload" alignment="1" pref="271" max="32767" attributes="1"/>
+                                  <Component id="jButtonSend" alignment="1" pref="259" max="32767" attributes="1"/>
+                                  <Component id="jButtonView" alignment="1" pref="259" max="32767" attributes="1"/>
+                                  <Component id="jButtonDump" alignment="1" pref="259" max="32767" attributes="1"/>
+                              </Group>
+                              <EmptySpace max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jLabelResults" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Group type="102" alignment="0" attributes="0">
+                                          <Group type="103" groupAlignment="0" attributes="0">
+                                              <Component id="jLabel22" alignment="0" min="-2" max="-2" attributes="0"/>
+                                              <Group type="102" alignment="0" attributes="0">
+                                                  <EmptySpace min="10" pref="10" max="10" attributes="0"/>
+                                                  <Component id="jPanelThumbnail" min="-2" max="-2" attributes="0"/>
+                                              </Group>
+                                          </Group>
+                                          <EmptySpace pref="129" max="32767" attributes="0"/>
+                                          <Component id="jLabelTime" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                                  <EmptySpace max="-2" attributes="0"/>
+                              </Group>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                    <DimensionLayout dim="1">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace pref="92" max="32767" attributes="0"/>
+                              <Component id="jButtonExport" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                              <Component id="jButtonDownload" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                              <Component id="jButtonSend" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                              <Component id="jButtonView" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
+                              <Component id="jButtonDump" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Component id="jLabelResults" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="3" attributes="0">
+                                      <Component id="jLabel22" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabelTime" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace pref="21" max="32767" attributes="0"/>
+                                  <Component id="jPanelThumbnail" min="-2" max="-2" attributes="1"/>
+                                  <EmptySpace min="-2" pref="53" max="-2" attributes="0"/>
+                              </Group>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JButton" name="jButtonSend">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Send"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonSendActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabelResults">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="jLabel2"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="jButtonDump">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Dump"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonDumpActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="jButtonDownload">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Download"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonDownloadActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabelTime">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="<<results time>>"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JLabel" name="jLabel22">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Time Results(ms):"/>
+                      </Properties>
+                    </Component>
+                    <Component class="javax.swing.JButton" name="jButtonView">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="View"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonViewActionPerformed"/>
+                      </Events>
+                    </Component>
+                    <Container class="javax.swing.JPanel" name="jPanelThumbnail">
+
+                      <Layout>
+                        <DimensionLayout dim="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <EmptySpace min="0" pref="67" max="32767" attributes="0"/>
+                          </Group>
+                        </DimensionLayout>
+                        <DimensionLayout dim="1">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <EmptySpace min="0" pref="62" max="32767" attributes="0"/>
+                          </Group>
+                        </DimensionLayout>
+                      </Layout>
+                    </Container>
+                    <Component class="javax.swing.JButton" name="jButtonExport">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Export"/>
+                        <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                          <Dimension value="[82, 29]"/>
+                        </Property>
+                        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                          <Dimension value="[82, 29]"/>
+                        </Property>
+                        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                          <Dimension value="[82, 29]"/>
+                        </Property>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonExportActionPerformed"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+                  <AuxValues>
+                    <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+                  </AuxValues>
+
+                  <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+                  <SubComponents>
+                    <Component class="javax.swing.JTree" name="jTreeResults">
+                      <Properties>
+                        <Property name="model" type="javax.swing.tree.TreeModel" editor="org.netbeans.modules.form.ComponentChooserEditor">
+                          <ComponentRef name="null"/>
+                        </Property>
+                        <Property name="rowHeight" type="int" value="15"/>
+                        <Property name="toggleClickCount" type="int" value="3"/>
+                      </Properties>
+                      <Events>
+                        <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jTreeResultsMouseClicked"/>
+                        <EventHandler event="treeExpanded" listener="javax.swing.event.TreeExpansionListener" parameters="javax.swing.event.TreeExpansionEvent" handler="jTreeResultsTreeExpanded"/>
+                        <EventHandler event="valueChanged" listener="javax.swing.event.TreeSelectionListener" parameters="javax.swing.event.TreeSelectionEvent" handler="jTreeResultsValueChanged"/>
+                        <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTreeResultsKeyReleased"/>
+                      </Events>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Container class="javax.swing.JPanel" name="jPanel6">
+
+                  <Layout>
+                    <DimensionLayout dim="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace pref="474" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                    </DimensionLayout>
+                    <DimensionLayout dim="1">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                    </DimensionLayout>
+                  </Layout>
+                  <SubComponents>
+                    <Component class="javax.swing.JLabel" name="jLabel2">
+                      <Properties>
+                        <Property name="text" type="java.lang.String" value="Search Range:"/>
+                      </Properties>
+                    </Component>
+                  </SubComponents>
+                </Container>
+                <Component class="javax.swing.JSeparator" name="jSeparator1">
+                </Component>
+                <Component class="javax.swing.JSeparator" name="jSeparator2">
+                  <Properties>
+                    <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                      <Dimension value="[50, 10]"/>
+                    </Property>
+                  </Properties>
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+      <Properties>
+        <Property name="dividerSize" type="int" value="2"/>
+        <Property name="orientation" type="int" value="0"/>
+        <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[2147483647, 100]"/>
+        </Property>
+        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[606, 100]"/>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
+          <BorderConstraints direction="North"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel8">
+          <Properties>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[604, 80]"/>
+            </Property>
+          </Properties>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+              <JSplitPaneConstraints position="top"/>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonServices" min="-2" pref="79" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonPreferences" min="-2" pref="79" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonLogs" min="-2" pref="79" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonPeers" min="-2" pref="79" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonClientPreferences" min="-2" pref="79" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="102" max="-2" attributes="0"/>
+                      <Component id="jSeparator3" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="752" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" attributes="0">
+                              <EmptySpace min="32" pref="32" max="32" attributes="0"/>
+                              <Component id="jSeparator3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                                  <Component id="jButtonClientPreferences" alignment="0" min="0" pref="0" max="32767" attributes="3"/>
+                                  <Component id="jButtonPeers" alignment="0" min="0" pref="0" max="32767" attributes="1"/>
+                                  <Component id="jButtonLogs" alignment="0" min="0" pref="0" max="32767" attributes="1"/>
+                                  <Component id="jButtonPreferences" alignment="0" min="0" pref="0" max="32767" attributes="3"/>
+                                  <Component id="jButtonServices" alignment="0" pref="64" max="32767" attributes="1"/>
+                              </Group>
+                          </Group>
+                      </Group>
+                      <EmptySpace min="-2" pref="124" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="jButtonServices">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("services.gif"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Services"/>
+                <Property name="horizontalTextPosition" type="int" value="0"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="verticalTextPosition" type="int" value="3"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonServicesActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonPreferences">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("config.gif"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Preferences"/>
+                <Property name="horizontalTextPosition" type="int" value="0"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="verticalTextPosition" type="int" value="3"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonPreferencesActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JSeparator" name="jSeparator3">
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonLogs">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("log.gif"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Logs"/>
+                <Property name="horizontalTextPosition" type="int" value="0"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="verticalTextPosition" type="int" value="3"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonLogsActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonPeers">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("peers.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="P2P Peers"/>
+                <Property name="horizontalTextPosition" type="int" value="0"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="verticalTextPosition" type="int" value="3"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonPeersActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonClientPreferences">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("settings.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Client Prefs"/>
+                <Property name="horizontalTextPosition" type="int" value="0"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[80, 80]"/>
+                </Property>
+                <Property name="verticalTextPosition" type="int" value="3"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonClientPreferencesActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.java
new file mode 100755
index 0000000..d484550
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/MainWindow.java
@@ -0,0 +1,3304 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * MainWindow.java
+ *
+ * Created on 9 de Novembro de 2007, 11:25
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import org.apache.commons.codec.binary.Base64;
+import org.jvnet.substance.SubstanceLookAndFeel;
+import org.jvnet.substance.skin.*;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.ClientSettings;
+import pt.ua.dicoogle.core.QueryHistorySupport;
+import pt.ua.dicoogle.plugins.NetworkMember;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.RFileBrowser.FileAction;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFileChooser;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.client.ClientCore;
+import pt.ua.dicoogle.rGUI.client.UIHelper.DisplayJAI;
+import pt.ua.dicoogle.rGUI.client.UIHelper.OSXAdapter;
+import pt.ua.dicoogle.rGUI.client.UIHelper.Result2Tree;
+import pt.ua.dicoogle.rGUI.client.UIHelper.TrayIconCreator;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.rGUI.fileTransfer.FileReceiver;
+import pt.ua.dicoogle.rGUI.fileTransfer.TransferStatus;
+import pt.ua.dicoogle.rGUI.server.controllers.PluginController4user;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.utils.Dicom2JPEG;
+
+import javax.imageio.ImageIO;
+import javax.swing.GroupLayout.Group;
+import javax.swing.GroupLayout.ParallelGroup;
+import javax.swing.GroupLayout.SequentialGroup;
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.image.RenderedImage;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.text.SimpleDateFormat;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
+
+/**
+ * Dicoogle GUI Main form
+ *
+ * @author Filipe Freitas
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Marco Pereira
+ * @author João Pereira
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ * @author Carlos Ferreira <c.ferreira at ua.pt>
+ * @author Frederico Valente
+ */
+ at Deprecated
+public class MainWindow extends javax.swing.JFrame {
+
+    private Result2Tree searchTree;
+    private static MainWindow instance = null;
+    private static Semaphore sem = new Semaphore(1, true);
+    private ClientCore clientCore;
+    //private DefaultMutableTreeNode top = null;
+
+    /*
+     * Information about last query executed
+     * It is usefull to the Export Module
+     */
+    private String lastQueryExecuted;
+    private boolean lastQueryKeywords;
+    private boolean lastQueryAdvanced;
+    private ArrayList<javax.swing.JCheckBox> ranges;
+
+    //a popup menu for plugin extension on retrieved results
+    private JPopupMenu popupMenu = new JPopupMenu();
+
+    public static synchronized MainWindow getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new MainWindow();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+    private final TaskList taskList;
+
+    /**
+     * Creates new form MainWindow
+     */
+    private MainWindow() {
+        ranges = new ArrayList<>();
+        List<String> names = null;
+        try {
+            names = PluginController4user.getInstance().getPluginNames();
+            for (String name : names) {
+                JCheckBox newJCB = new JCheckBox(name);
+                if (PluginController4user.getInstance().isLocalPlugin(name)) {
+                    newJCB.setSelected(true);
+                }
+                this.ranges.add(newJCB);
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+
+        initComponents();
+
+        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
+        jPanel6.setLayout(jPanel6Layout);
+        SequentialGroup groupBoxesH = jPanel6Layout.createSequentialGroup().addComponent(jLabel2);
+        ParallelGroup groupBoxesV = jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE).addComponent(jLabel2);
+
+        for (JCheckBox cbox : this.ranges) {
+            groupBoxesH.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED).addComponent(cbox);
+            groupBoxesV.addComponent(cbox);
+        }
+
+        Group groupH = jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).
+                addGroup(groupBoxesH.addContainerGap(10, Short.MAX_VALUE));
+
+        Group groupV = jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(jPanel6Layout.createSequentialGroup().addGroup(groupBoxesV).addContainerGap(5, Short.MAX_VALUE));
+
+        jPanel6Layout.setHorizontalGroup(groupH);
+        jPanel6Layout.setVerticalGroup(groupV);
+
+        Image image = getImage("trayicon.gif");
+        this.setIconImage(image);
+
+        clientCore = ClientCore.getInstance();
+
+        if (!clientCore.isAdmin()) {
+            jMenu10.setVisible(false);
+            jMenuItemShutdown.setVisible(false);
+            jMenuDirScan2.setVisible(false);
+
+            //jPanel8.setVisible(false);
+            jButtonServices.setVisible(false);
+            jButtonPreferences.setVisible(false);
+            jButtonLogs.setVisible(false);
+        }
+
+        if (!clientCore.isUser()) {
+            jPanel5.setVisible(false);
+            jButtonClientPreferences.setVisible(false);
+        } else {
+            searchTree = Result2Tree.getInstance();
+        }
+
+        if (Main.isFixedClient()) {
+            jMenuItemShutdown.setVisible(false);
+
+        } else {
+            jMenuItem7.setVisible(false);
+        }
+
+        jLabelResults.setText("Enter your terms and hit the button.");
+        SelectDefaultSearch.setSelected(true);
+        SelectAdvancedSearch.setSelected(false);
+        jPanel2.setVisible(false);
+        ModalSelectNone.setSelected(false);
+        ModalSelectAll.setSelected(true);
+        ModalCR.setSelected(true);
+        ModalCT.setSelected(true);
+        ModalDX.setSelected(true);
+        ModalES.setSelected(true);
+        ModalMG.setSelected(true);
+        ModalMR.setSelected(true);
+        ModalNM.setSelected(true);
+        ModalOT.setSelected(true);
+        ModalPT.setSelected(true);
+        ModalRF.setSelected(true);
+        ModalSC.setSelected(true);
+        ModalUS.setSelected(true);
+        ModalXA.setSelected(true);
+
+        StudyDateRangeInitialBoundary.setEnabled(false);
+        StudyDateRangeTerminalBoundary.setEnabled(false);
+        DateRange.setSelected(false);
+        ExactDate.setSelected(true);
+
+        StudyDateRangeInitialBoundaryActivation.setEnabled(false);
+        StudyDateRangeTerminalBoundaryActivation.setEnabled(false);
+        StudyDateRangeInitialBoundary.setEnabled(false);
+        StudyDateRangeTerminalBoundary.setEnabled(false);
+
+        //tree view init
+        jTreeResults.setModel(new DefaultTreeModel(Result2Tree.getInstance().getTop()));
+        jTreeResults.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+        jButtonDownload.setEnabled(false);
+        jButtonView.setEnabled(false);
+        jButtonDump.setEnabled(false);
+        this.resizeWindow();
+        registerForMacOSXEvents();
+        centerWindow();
+
+//////////////////////////////////////////////////////////////
+        /**
+         * This search is needed to autocomplete
+         */
+        /*
+         QueryResults q = new QueryResults("*:*");
+        
+        
+         List<String> items = q.getFields();
+        
+        
+        
+         boolean strictMatching = false;
+         AutoCompleteDecorator.decorate(jTextFieldQuery, items, strictMatching);
+         *
+         */
+        //plugins v2
+        try {
+            List<JPanel> panels = PluginController4user.getInstance().getTabPanels();
+            if (panels != null) {
+                for (JPanel panel : panels) {
+                    tabPanel.add(panel);
+                }
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+
+        try {
+            List<JMenuItem> menus = PluginController4user.getInstance().getPluginMenus();
+            if (menus != null) {
+                for (JMenuItem menu : menus) {
+                    pluginMenu.add(menu);
+                }
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+
+        try {
+            System.err.println("Checking for plugins requiring gui expansion.,.");
+            List<JMenuItem> items = PluginController4user.getInstance().getRightButtonItems();
+            if (items != null) {
+                for (JMenuItem item : items) {
+                    popupMenu.add(item);
+                }
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+
+        taskList = new TaskList();
+        taskList.setName("Task Progress");
+        tabPanel.add(taskList);
+
+    }
+
+    /**
+     * Center the main Window taking into account the Screen Size
+     */
+    private void centerWindow() {
+        // Positions the window in the center of screen
+        int width = this.getWidth();
+        int height = this.getHeight();
+        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+        int x = (screen.width - width) / 2;
+        int y = (screen.height - height) / 2;
+        setBounds(x, y, width, height);
+    }
+
+    private void resizeWindow() {
+        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
+        this.setSize(screen.width - 30, screen.height - 50);
+    }
+
+    /**
+     * Register the Events to Quit and About if Dicoogle is running on Mac_OSX
+     */
+    private void registerForMacOSXEvents() {
+        if (Main.MAC_OS_X) {
+            try {
+                //System.out.println("Registering MAC_OSX Events");
+
+                // Generate and register the OSXAdapter, passing it a hash of all the methods we wish to
+                // use as delegates for various com.apple.eawt.ApplicationListener methods
+                if (Main.isFixedClient()) {
+                    OSXAdapter.setQuitHandler(this, getClass().getDeclaredMethod("exit", (Class[]) null));
+                } else {
+                    OSXAdapter.setQuitHandler(this, getClass().getDeclaredMethod("exitClient", (Class[]) null));
+                }
+
+                OSXAdapter.setAboutHandler(this, getClass().getDeclaredMethod("about", (Class[]) null));
+                //OSXAdapter.setPreferencesHandler(this, getClass().getDeclaredMethod("preferences", (Class[])null));
+                //OSXAdapter.setFileHandler(this, getClass().getDeclaredMethod("loadImageFile", new Class[] { String.class }));
+
+            } catch (Exception e) {
+                System.err.println("Error while loading the OSXAdapter:");
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void exit() {
+        jMenuItem1ActionPerformed(null);
+    }
+
+    public void exitClient() {
+        jMenuItem11ActionPerformed(null);
+    }
+
+    public void about() {
+        jMenuItem3ActionPerformed(null);
+    }
+
+    /**
+     * ************************************************
+     * Private Methods
+     *************************************************
+     */
+    /**
+     * Stops the window from minimizing to tray while in options screen
+     */
+    private void showOptions() {
+    }
+
+    private void cleanThumbnails() {
+//        Result2Tree.showImage("Image Thumbnail", null, jPanelThumbnail);
+        jPanelThumbnail.setSize(64, 64);
+        repaint();
+        return;
+    }
+
+    /**
+     *  * @author Joaoffr  <joaoffr at ua.pt>
+     *  * @author DavidP   <davidp at ua.pt>
+     * @param t
+     * @return
+     */
+    private String convMillisToTimeString(long t) {
+        long milis = t % 1000;
+        t /= 1000;
+        long segs = t % 60;
+        t /= 60;
+        long mins = t % 60;
+        t /= 60;
+        long hours = t % 60;
+        t /= 24;
+        long days = t;
+
+        return String.format("%d:%02d:%02d:%02d", days, hours, mins, segs);
+    }
+
+    private void dcm2JPEG(int thumbnailSize) {
+
+        /**
+         * Why couldn't? It works!
+         *
+         * if (System.getProperty("os.name").toUpperCase().indexOf("MAC OS") !=
+         * -1) { JOptionPane.showMessageDialog(this, "Operation Not Available to
+         * MAC OS.", "Missing JAI Tool", JOptionPane.WARNING_MESSAGE); return; }
+         */
+        String pathDir = ".";
+
+        JFileChooser chooser = new JFileChooser();
+        chooser.setCurrentDirectory(new java.io.File(pathDir));
+        chooser.setDialogTitle("Dicoogle Dcm2JPG - Select DICOM File");
+        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+        //chooser.setFileFilter(arg0)
+        chooser.setAcceptAllFileFilterUsed(false);
+
+        if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+            File filePath = new File(chooser.getSelectedFile().toString());
+            if (filePath.exists() && filePath.isFile() && filePath.canRead()) {
+                File jpgFile = new File(filePath.getAbsolutePath() + ".jpg");
+                Dicom2JPEG.convertDicom2Jpeg(filePath, jpgFile, thumbnailSize);
+            }
+        }
+    }
+
+    /**
+     * @return ArrayList<String> with selected items in the tree
+     */
+    private ArrayList<String> getSelectedLocalFiles() {
+        ArrayList<String> files = new ArrayList<String>();
+
+        TreePath path = jTreeResults.getSelectionPath();
+
+        // Tree Root is not permited
+        if (path == null || path.getPathCount() < 2) {
+            return null;
+        }
+
+        jTreeResults.expandPath(path);
+
+        if (path != null) {
+            DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
+
+            // recieves all childs
+            ArrayList<DefaultMutableTreeNode> childs = getLocalLeafs(node, path);
+
+            Iterator<DefaultMutableTreeNode> it = childs.iterator();
+
+            // converts TreeNodes to filePaths
+            while (it.hasNext()) {
+                Object obj = it.next().getUserObject();
+
+                if (SearchResult.class.isInstance(obj)) {
+                    files.add(obj.toString());
+                }
+            }
+        }
+
+        return files;
+    }
+
+    private ArrayList<DefaultMutableTreeNode> getLocalLeafs(DefaultMutableTreeNode node, TreePath path) {
+        ArrayList<DefaultMutableTreeNode> list = new ArrayList<DefaultMutableTreeNode>();
+        TreePath temp;
+
+        if (node.isLeaf()) {
+            list.add(node);
+        } else {
+            Enumeration<DefaultMutableTreeNode> en = node.children();
+
+            while (en.hasMoreElements()) {
+                DefaultMutableTreeNode elem = en.nextElement();
+
+                temp = path.pathByAddingChild(elem);
+                jTreeResults.expandPath(temp);
+
+                list.addAll(getLocalLeafs(elem, temp));
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        tabPanel = new javax.swing.JTabbedPane();
+        jScrollPane2 = new javax.swing.JScrollPane();
+        jPanel5 = new javax.swing.JPanel();
+        SelectAdvancedSearch = new javax.swing.JRadioButton();
+        SelectDefaultSearch = new javax.swing.JRadioButton();
+        jLabel5 = new javax.swing.JLabel();
+        jPanel2 = new javax.swing.JPanel();
+        jLabel7 = new javax.swing.JLabel();
+        jLabel8 = new javax.swing.JLabel();
+        jLabel9 = new javax.swing.JLabel();
+        jLabel10 = new javax.swing.JLabel();
+        jLabel11 = new javax.swing.JLabel();
+        OperatorName = new javax.swing.JTextField();
+        Physician = new javax.swing.JTextField();
+        PatientGender = new javax.swing.JComboBox();
+        PatientName = new javax.swing.JTextField();
+        InstitutionName = new javax.swing.JTextField();
+        jPanel3 = new javax.swing.JPanel();
+        ModalCR = new javax.swing.JCheckBox();
+        ModalMG = new javax.swing.JCheckBox();
+        ModalPT = new javax.swing.JCheckBox();
+        ModalCT = new javax.swing.JCheckBox();
+        ModalMR = new javax.swing.JCheckBox();
+        ModalRF = new javax.swing.JCheckBox();
+        ModalDX = new javax.swing.JCheckBox();
+        ModalNM = new javax.swing.JCheckBox();
+        ModalSC = new javax.swing.JCheckBox();
+        ModalES = new javax.swing.JCheckBox();
+        ModalOT = new javax.swing.JCheckBox();
+        ModalUS = new javax.swing.JCheckBox();
+        ModalXA = new javax.swing.JCheckBox();
+        jLabel14 = new javax.swing.JLabel();
+        ModalSelectAll = new javax.swing.JRadioButton();
+        ModalSelectNone = new javax.swing.JRadioButton();
+        jLabel19 = new javax.swing.JLabel();
+        jLabel20 = new javax.swing.JLabel();
+        PatientID = new javax.swing.JTextField();
+        AdvancedSearchButton = new javax.swing.JButton();
+        ResetFields = new javax.swing.JButton();
+        jPanel4 = new javax.swing.JPanel();
+        StudyDateRangeInitialBoundaryActivation = new javax.swing.JCheckBox();
+        StudyDateRangeInitialBoundary = new javax.swing.JTextField();
+        jLabel16 = new javax.swing.JLabel();
+        StudyDateRangeTerminalBoundaryActivation = new javax.swing.JCheckBox();
+        StudyDateRangeTerminalBoundary = new javax.swing.JTextField();
+        StudyDate = new javax.swing.JTextField();
+        jLabel13 = new javax.swing.JLabel();
+        jLabel15 = new javax.swing.JLabel();
+        jLabel12 = new javax.swing.JLabel();
+        jLabel4 = new javax.swing.JLabel();
+        ExactDate = new javax.swing.JRadioButton();
+        DateRange = new javax.swing.JRadioButton();
+        jLabel17 = new javax.swing.JLabel();
+        jPanel1 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jTextFieldQuery = new javax.swing.JTextField();
+        jButtonSearch = new javax.swing.JButton();
+        SearchTips = new javax.swing.JButton();
+        jCheckBoxKeywords = new javax.swing.JCheckBox();
+        jButtonQueryHistory = new javax.swing.JButton();
+        jPanel9 = new javax.swing.JPanel();
+        jButtonSend = new javax.swing.JButton();
+        jLabelResults = new javax.swing.JLabel();
+        jButtonDump = new javax.swing.JButton();
+        jButtonDownload = new javax.swing.JButton();
+        jLabelTime = new javax.swing.JLabel();
+        jLabel22 = new javax.swing.JLabel();
+        jButtonView = new javax.swing.JButton();
+        jPanelThumbnail = new javax.swing.JPanel();
+        jButtonExport = new javax.swing.JButton();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jTreeResults = new javax.swing.JTree();
+        jPanel6 = new javax.swing.JPanel();
+        jLabel2 = new javax.swing.JLabel();
+        jSeparator1 = new javax.swing.JSeparator();
+        jSeparator2 = new javax.swing.JSeparator();
+        jSplitPane1 = new javax.swing.JSplitPane();
+        jPanel8 = new javax.swing.JPanel();
+        jButtonServices = new javax.swing.JButton();
+        jButtonPreferences = new javax.swing.JButton();
+        jSeparator3 = new javax.swing.JSeparator();
+        jButtonLogs = new javax.swing.JButton();
+        jButtonPeers = new javax.swing.JButton();
+        jButtonClientPreferences = new javax.swing.JButton();
+        jMenuBar3 = new javax.swing.JMenuBar();
+        jMenu9 = new javax.swing.JMenu();
+        jMenuItemChangePassword = new javax.swing.JMenuItem();
+        jMenuDirScan2 = new javax.swing.JMenuItem();
+        jMenuDirScanResume = new javax.swing.JMenuItem();
+        jMenuItemShutdown = new javax.swing.JMenuItem();
+        jMenuItem11 = new javax.swing.JMenuItem();
+        jMenuItem7 = new javax.swing.JMenuItem();
+        jMenu10 = new javax.swing.JMenu();
+        jMenuItemPreferences = new javax.swing.JMenuItem();
+        jMenuItemServices = new javax.swing.JMenuItem();
+        jMenuItem10 = new javax.swing.JMenuItem();
+        jMenuItemUsers = new javax.swing.JMenuItem();
+        jMenuItemActiveUsers = new javax.swing.JMenuItem();
+        jMenuTools2 = new javax.swing.JMenu();
+        jMenuItemDcm2jpeg2 = new javax.swing.JMenuItem();
+        jMenu11 = new javax.swing.JMenu();
+        jMenuItem1 = new javax.swing.JMenuItem();
+        jMenuItem2 = new javax.swing.JMenuItem();
+        jMenuItem3 = new javax.swing.JMenuItem();
+        jMenuItem4 = new javax.swing.JMenuItem();
+        jMenuItem5 = new javax.swing.JMenuItem();
+        jMenuItem6 = new javax.swing.JMenuItem();
+        jMenuItem8 = new javax.swing.JMenuItem();
+        pluginMenu = new javax.swing.JMenu();
+        jMenu12 = new javax.swing.JMenu();
+        jMenuItem9 = new javax.swing.JMenuItem();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+        setTitle("Dicoogle PACS Archive");
+        setMinimumSize(new java.awt.Dimension(700, 526));
+        setName("MainWindow"); // NOI18N
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowOpened(java.awt.event.WindowEvent evt) {
+                formWindowOpened(evt);
+            }
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+            public void windowIconified(java.awt.event.WindowEvent evt) {
+                formWindowIconified(evt);
+            }
+            public void windowDeiconified(java.awt.event.WindowEvent evt) {
+                formWindowDeiconified(evt);
+            }
+        });
+
+        jScrollPane2.setPreferredSize(new java.awt.Dimension(602, 602));
+
+        jPanel5.setMaximumSize(new java.awt.Dimension(1197, 100));
+        jPanel5.setPreferredSize(new java.awt.Dimension(1197, 100));
+
+        SelectAdvancedSearch.setText("Advanced search");
+        SelectAdvancedSearch.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                SelectAdvancedSearchActionPerformed(evt);
+            }
+        });
+
+        SelectDefaultSearch.setText("Default search");
+        SelectDefaultSearch.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                SelectDefaultSearchActionPerformed(evt);
+            }
+        });
+
+        jLabel5.setText("Search type:");
+
+        jLabel7.setText("Patient Name:");
+
+        jLabel8.setText("Patient Gender:");
+
+        jLabel9.setText("Institution Name:");
+
+        jLabel10.setText("Physician:");
+
+        jLabel11.setText("Operator Name:");
+
+        OperatorName.setText("(All operators)");
+
+        Physician.setText("(All physicians)");
+
+        PatientGender.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "All", "Male", "Female" }));
+
+        PatientName.setText("(All patients)");
+
+        InstitutionName.setText("(All institutions)");
+
+        ModalCR.setText("CR");
+        ModalCR.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalCRActionPerformed(evt);
+            }
+        });
+
+        ModalMG.setText("MG");
+        ModalMG.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalMGActionPerformed(evt);
+            }
+        });
+
+        ModalPT.setText("PT");
+        ModalPT.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalPTActionPerformed(evt);
+            }
+        });
+
+        ModalCT.setText("CT");
+        ModalCT.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalCTActionPerformed(evt);
+            }
+        });
+
+        ModalMR.setText("MR");
+        ModalMR.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalMRActionPerformed(evt);
+            }
+        });
+
+        ModalRF.setText("RF");
+        ModalRF.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalRFActionPerformed(evt);
+            }
+        });
+
+        ModalDX.setText("DX");
+        ModalDX.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalDXActionPerformed(evt);
+            }
+        });
+
+        ModalNM.setText("NM");
+        ModalNM.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalNMActionPerformed(evt);
+            }
+        });
+
+        ModalSC.setText("SC");
+        ModalSC.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalSCActionPerformed(evt);
+            }
+        });
+
+        ModalES.setText("ES");
+        ModalES.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalESActionPerformed(evt);
+            }
+        });
+
+        ModalOT.setText("OT");
+        ModalOT.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalOTActionPerformed(evt);
+            }
+        });
+
+        ModalUS.setText("US");
+        ModalUS.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalUSActionPerformed(evt);
+            }
+        });
+
+        ModalXA.setText("XA");
+        ModalXA.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalXAActionPerformed(evt);
+            }
+        });
+
+        jLabel14.setText("Modality:");
+
+        ModalSelectAll.setText("Select all");
+        ModalSelectAll.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalSelectAllActionPerformed(evt);
+            }
+        });
+
+        ModalSelectNone.setText("Select none");
+        ModalSelectNone.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ModalSelectNoneActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
+        jPanel3.setLayout(jPanel3Layout);
+        jPanel3Layout.setHorizontalGroup(
+            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel3Layout.createSequentialGroup()
+                        .addComponent(jLabel14)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(ModalSelectAll)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(ModalSelectNone))
+                    .addGroup(jPanel3Layout.createSequentialGroup()
+                        .addGap(6, 6, 6)
+                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                            .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                .addComponent(ModalDX)
+                                .addComponent(ModalCT))
+                            .addComponent(ModalCR))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(ModalMG)
+                            .addComponent(ModalNM)
+                            .addComponent(ModalMR))
+                        .addGap(6, 6, 6)
+                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(ModalPT)
+                            .addComponent(ModalSC)
+                            .addComponent(ModalRF))
+                        .addGap(12, 12, 12)
+                        .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(ModalUS)
+                            .addComponent(ModalXA)
+                            .addComponent(ModalOT))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(ModalES)))
+                .addGap(202, 202, 202))
+        );
+        jPanel3Layout.setVerticalGroup(
+            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel3Layout.createSequentialGroup()
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel14)
+                    .addComponent(ModalSelectAll)
+                    .addComponent(ModalSelectNone))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(ModalPT)
+                    .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(ModalMG)
+                        .addComponent(ModalCR, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(ModalXA)
+                    .addComponent(ModalES))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(ModalUS, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(ModalRF)
+                    .addComponent(ModalMR)
+                    .addComponent(ModalCT))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(ModalOT)
+                    .addComponent(ModalSC)
+                    .addComponent(ModalNM)
+                    .addComponent(ModalDX))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jLabel19.setText("Note: Only what you change will modify the default query.");
+
+        jLabel20.setText("Patient ID:");
+
+        PatientID.setText("(All IDs)");
+
+        AdvancedSearchButton.setText("Search");
+        AdvancedSearchButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                AdvancedSearchButtonActionPerformed(evt);
+            }
+        });
+
+        ResetFields.setText("Reset fields");
+        ResetFields.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ResetFieldsActionPerformed(evt);
+            }
+        });
+
+        StudyDateRangeInitialBoundaryActivation.setText("From:");
+        StudyDateRangeInitialBoundaryActivation.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                StudyDateRangeInitialBoundaryActivationActionPerformed(evt);
+            }
+        });
+
+        StudyDateRangeInitialBoundary.setText("(Beginning)");
+
+        jLabel16.setText("--");
+
+        StudyDateRangeTerminalBoundaryActivation.setText("To:");
+        StudyDateRangeTerminalBoundaryActivation.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                StudyDateRangeTerminalBoundaryActivationActionPerformed(evt);
+            }
+        });
+
+        StudyDateRangeTerminalBoundary.setText("(Today)");
+
+        StudyDate.setText("(All dates)");
+
+        jLabel13.setText("(yyyymmdd form)");
+
+        jLabel15.setText("Date Range:");
+
+        jLabel12.setText("Date:");
+
+        jLabel4.setText("Study Date search type:");
+
+        ExactDate.setText("Exact Date");
+        ExactDate.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                ExactDateActionPerformed(evt);
+            }
+        });
+
+        DateRange.setText("Date Range");
+        DateRange.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                DateRangeActionPerformed(evt);
+            }
+        });
+
+        jLabel17.setText("(yyyymmdd form)");
+
+        javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
+        jPanel4.setLayout(jPanel4Layout);
+        jPanel4Layout.setHorizontalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addGap(8, 8, 8)
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addComponent(jLabel4)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(ExactDate)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(DateRange))
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addComponent(jLabel12)
+                        .addGap(2, 2, 2)
+                        .addComponent(StudyDate, javax.swing.GroupLayout.PREFERRED_SIZE, 87, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel13)))
+                .addGap(71, 71, 71))
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addGap(6, 6, 6)
+                .addComponent(jLabel15)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addComponent(StudyDateRangeInitialBoundary, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel16))
+                    .addComponent(StudyDateRangeInitialBoundaryActivation))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addComponent(StudyDateRangeTerminalBoundary, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                        .addComponent(jLabel17))
+                    .addComponent(StudyDateRangeTerminalBoundaryActivation))
+                .addContainerGap())
+        );
+        jPanel4Layout.setVerticalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(ExactDate)
+                    .addComponent(DateRange)
+                    .addComponent(jLabel4))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(StudyDate, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jLabel13)
+                    .addComponent(jLabel12))
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addGap(10, 10, 10)
+                        .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(StudyDateRangeInitialBoundaryActivation)
+                            .addComponent(StudyDateRangeTerminalBoundaryActivation)
+                            .addComponent(jLabel15)))
+                    .addGroup(jPanel4Layout.createSequentialGroup()
+                        .addGap(35, 35, 35)
+                        .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(StudyDateRangeInitialBoundary, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
+                            .addComponent(jLabel16)
+                            .addComponent(StudyDateRangeTerminalBoundary, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                            .addComponent(jLabel17))))
+                .addContainerGap())
+        );
+
+        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel2Layout.createSequentialGroup()
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jLabel8)
+                            .addComponent(jLabel9)
+                            .addComponent(jLabel10)
+                            .addComponent(jLabel11))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                            .addComponent(PatientID)
+                            .addComponent(PatientGender, 0, 118, Short.MAX_VALUE)
+                            .addComponent(Physician)
+                            .addComponent(InstitutionName)
+                            .addComponent(PatientName)
+                            .addComponent(OperatorName)))
+                    .addGroup(jPanel2Layout.createSequentialGroup()
+                        .addComponent(AdvancedSearchButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(ResetFields))
+                    .addComponent(jLabel19)
+                    .addComponent(jLabel7)
+                    .addComponent(jLabel20))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(381, Short.MAX_VALUE))
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel2Layout.createSequentialGroup()
+                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel2Layout.createSequentialGroup()
+                        .addGap(14, 14, 14)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(AdvancedSearchButton)
+                            .addComponent(ResetFields))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel19)
+                        .addGap(18, 18, 18)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel7)
+                            .addComponent(PatientName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel20)
+                            .addComponent(PatientID, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel8)
+                            .addComponent(PatientGender, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel9)
+                            .addComponent(InstitutionName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel10)
+                            .addComponent(Physician, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                            .addComponent(jLabel11)
+                            .addComponent(OperatorName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                    .addGroup(jPanel2Layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, 96, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap())
+        );
+
+        jLabel1.setText("Search Pattern :");
+
+        jLabel3.setText("Regular expressions are supported (eg: A*).");
+
+        jTextFieldQuery.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jTextFieldQueryActionPerformed(evt);
+            }
+        });
+        jTextFieldQuery.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jTextFieldQueryKeyPressed(evt);
+            }
+        });
+
+        jButtonSearch.setText("Search");
+        jButtonSearch.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonSearchActionPerformed(evt);
+            }
+        });
+
+        SearchTips.setText("Search Tips");
+        SearchTips.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                SearchTipsActionPerformed(evt);
+            }
+        });
+
+        jCheckBoxKeywords.setSelected(true);
+        jCheckBoxKeywords.setText("keywords");
+
+        jButtonQueryHistory.setText("Query History");
+        jButtonQueryHistory.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonQueryHistoryActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 108, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jTextFieldQuery, javax.swing.GroupLayout.PREFERRED_SIZE, 328, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addGap(18, 18, 18)
+                        .addComponent(jCheckBoxKeywords))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jButtonSearch)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(SearchTips)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jButtonQueryHistory))
+                    .addComponent(jLabel3))
+                .addContainerGap(683, Short.MAX_VALUE))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                    .addComponent(jButtonSearch, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(SearchTips, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(jButtonQueryHistory, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel1)
+                    .addComponent(jTextFieldQuery, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jCheckBoxKeywords))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel3)
+                .addContainerGap(37, Short.MAX_VALUE))
+        );
+
+        jButtonSend.setText("Send");
+        jButtonSend.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonSendActionPerformed(evt);
+            }
+        });
+
+        jLabelResults.setText("jLabel2");
+
+        jButtonDump.setText("Dump");
+        jButtonDump.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonDumpActionPerformed(evt);
+            }
+        });
+
+        jButtonDownload.setText("Download");
+        jButtonDownload.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonDownloadActionPerformed(evt);
+            }
+        });
+
+        jLabelTime.setText("<<results time>>");
+
+        jLabel22.setText("Time Results(ms):");
+
+        jButtonView.setText("View");
+        jButtonView.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonViewActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanelThumbnailLayout = new javax.swing.GroupLayout(jPanelThumbnail);
+        jPanelThumbnail.setLayout(jPanelThumbnailLayout);
+        jPanelThumbnailLayout.setHorizontalGroup(
+            jPanelThumbnailLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 67, Short.MAX_VALUE)
+        );
+        jPanelThumbnailLayout.setVerticalGroup(
+            jPanelThumbnailLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 62, Short.MAX_VALUE)
+        );
+
+        jButtonExport.setText("Export");
+        jButtonExport.setMaximumSize(new java.awt.Dimension(82, 29));
+        jButtonExport.setMinimumSize(new java.awt.Dimension(82, 29));
+        jButtonExport.setPreferredSize(new java.awt.Dimension(82, 29));
+        jButtonExport.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonExportActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9);
+        jPanel9.setLayout(jPanel9Layout);
+        jPanel9Layout.setHorizontalGroup(
+            jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel9Layout.createSequentialGroup()
+                .addGap(120, 120, 120)
+                .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jButtonExport, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
+                    .addComponent(jButtonDownload, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
+                    .addComponent(jButtonSend, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
+                    .addComponent(jButtonView, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
+                    .addComponent(jButtonDump, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE))
+                .addContainerGap())
+            .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                .addGroup(jPanel9Layout.createSequentialGroup()
+                    .addContainerGap()
+                    .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                        .addComponent(jLabelResults)
+                        .addGroup(jPanel9Layout.createSequentialGroup()
+                            .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                .addComponent(jLabel22)
+                                .addGroup(jPanel9Layout.createSequentialGroup()
+                                    .addGap(10, 10, 10)
+                                    .addComponent(jPanelThumbnail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 129, Short.MAX_VALUE)
+                            .addComponent(jLabelTime)))
+                    .addContainerGap()))
+        );
+        jPanel9Layout.setVerticalGroup(
+            jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel9Layout.createSequentialGroup()
+                .addContainerGap(92, Short.MAX_VALUE)
+                .addComponent(jButtonExport, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonDownload)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonSend)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonView)
+                .addGap(5, 5, 5)
+                .addComponent(jButtonDump)
+                .addContainerGap())
+            .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                .addGroup(jPanel9Layout.createSequentialGroup()
+                    .addContainerGap()
+                    .addComponent(jLabelResults)
+                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                    .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(jLabel22)
+                        .addComponent(jLabelTime))
+                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 21, Short.MAX_VALUE)
+                    .addComponent(jPanelThumbnail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addGap(53, 53, 53)))
+        );
+
+        jTreeResults.setModel(null);
+        jTreeResults.setRowHeight(15);
+        jTreeResults.setToggleClickCount(3);
+        jTreeResults.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jTreeResultsMouseClicked(evt);
+            }
+        });
+        jTreeResults.addTreeExpansionListener(new javax.swing.event.TreeExpansionListener() {
+            public void treeCollapsed(javax.swing.event.TreeExpansionEvent evt) {
+            }
+            public void treeExpanded(javax.swing.event.TreeExpansionEvent evt) {
+                jTreeResultsTreeExpanded(evt);
+            }
+        });
+        jTreeResults.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
+            public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
+                jTreeResultsValueChanged(evt);
+            }
+        });
+        jTreeResults.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyReleased(java.awt.event.KeyEvent evt) {
+                jTreeResultsKeyReleased(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jTreeResults);
+
+        jLabel2.setText("Search Range:");
+
+        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
+        jPanel6.setLayout(jPanel6Layout);
+        jPanel6Layout.setHorizontalGroup(
+            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel6Layout.createSequentialGroup()
+                .addComponent(jLabel2)
+                .addContainerGap(474, Short.MAX_VALUE))
+        );
+        jPanel6Layout.setVerticalGroup(
+            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jLabel2)
+        );
+
+        jSeparator2.setMaximumSize(new java.awt.Dimension(50, 10));
+
+        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
+        jPanel5.setLayout(jPanel5Layout);
+        jPanel5Layout.setHorizontalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 1279, Short.MAX_VALUE)
+            .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 1279, Short.MAX_VALUE)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel5Layout.createSequentialGroup()
+                        .addComponent(jLabel5)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(SelectDefaultSearch)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(SelectAdvancedSearch)
+                        .addGap(28, 28, 28)
+                        .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel5Layout.createSequentialGroup()
+                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 846, Short.MAX_VALUE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        jPanel5Layout.setVerticalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(jLabel5)
+                        .addComponent(SelectDefaultSearch)
+                        .addComponent(SelectAdvancedSearch))
+                    .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addGap(10, 10, 10)
+                .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addGap(15, 15, 15)
+                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jPanel9, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)))
+        );
+
+        jScrollPane2.setViewportView(jPanel5);
+
+        tabPanel.addTab("Search", jScrollPane2);
+
+        getContentPane().add(tabPanel, java.awt.BorderLayout.CENTER);
+
+        jSplitPane1.setDividerSize(2);
+        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
+        jSplitPane1.setMaximumSize(new java.awt.Dimension(2147483647, 100));
+        jSplitPane1.setPreferredSize(new java.awt.Dimension(606, 100));
+
+        jPanel8.setPreferredSize(new java.awt.Dimension(604, 80));
+
+        jButtonServices.setIcon(new ImageIcon(getImage("services.gif")));
+        jButtonServices.setText("Services");
+        jButtonServices.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonServices.setMaximumSize(new java.awt.Dimension(80, 80));
+        jButtonServices.setMinimumSize(new java.awt.Dimension(80, 80));
+        jButtonServices.setPreferredSize(new java.awt.Dimension(80, 80));
+        jButtonServices.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonServices.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonServicesActionPerformed(evt);
+            }
+        });
+
+        jButtonPreferences.setIcon(new ImageIcon(getImage("config.gif")));
+        jButtonPreferences.setText("Preferences");
+        jButtonPreferences.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonPreferences.setMaximumSize(new java.awt.Dimension(80, 80));
+        jButtonPreferences.setMinimumSize(new java.awt.Dimension(80, 80));
+        jButtonPreferences.setPreferredSize(new java.awt.Dimension(80, 80));
+        jButtonPreferences.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonPreferences.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonPreferencesActionPerformed(evt);
+            }
+        });
+
+        jButtonLogs.setIcon(new ImageIcon(getImage("log.gif")));
+        jButtonLogs.setText("Logs");
+        jButtonLogs.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonLogs.setMaximumSize(new java.awt.Dimension(80, 80));
+        jButtonLogs.setMinimumSize(new java.awt.Dimension(80, 80));
+        jButtonLogs.setPreferredSize(new java.awt.Dimension(80, 80));
+        jButtonLogs.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonLogs.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonLogsActionPerformed(evt);
+            }
+        });
+
+        jButtonPeers.setIcon(new ImageIcon(getImage("peers.png")));
+        jButtonPeers.setText("P2P Peers");
+        jButtonPeers.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonPeers.setMaximumSize(new java.awt.Dimension(80, 80));
+        jButtonPeers.setMinimumSize(new java.awt.Dimension(80, 80));
+        jButtonPeers.setPreferredSize(new java.awt.Dimension(80, 80));
+        jButtonPeers.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonPeers.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonPeersActionPerformed(evt);
+            }
+        });
+
+        jButtonClientPreferences.setIcon(new ImageIcon(getImage("settings.png")));
+        jButtonClientPreferences.setText("Client Prefs");
+        jButtonClientPreferences.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        jButtonClientPreferences.setMaximumSize(new java.awt.Dimension(80, 80));
+        jButtonClientPreferences.setMinimumSize(new java.awt.Dimension(80, 80));
+        jButtonClientPreferences.setPreferredSize(new java.awt.Dimension(80, 80));
+        jButtonClientPreferences.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        jButtonClientPreferences.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonClientPreferencesActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel8Layout = new javax.swing.GroupLayout(jPanel8);
+        jPanel8.setLayout(jPanel8Layout);
+        jPanel8Layout.setHorizontalGroup(
+            jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel8Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jButtonServices, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonPreferences, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonLogs, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonPeers, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonClientPreferences, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addGap(102, 102, 102)
+                .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(752, Short.MAX_VALUE))
+        );
+        jPanel8Layout.setVerticalGroup(
+            jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel8Layout.createSequentialGroup()
+                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel8Layout.createSequentialGroup()
+                        .addGap(32, 32, 32)
+                        .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(jPanel8Layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                            .addComponent(jButtonClientPreferences, 0, 0, Short.MAX_VALUE)
+                            .addComponent(jButtonPeers, 0, 0, Short.MAX_VALUE)
+                            .addComponent(jButtonLogs, 0, 0, Short.MAX_VALUE)
+                            .addComponent(jButtonPreferences, 0, 0, Short.MAX_VALUE)
+                            .addComponent(jButtonServices, javax.swing.GroupLayout.PREFERRED_SIZE, 64, Short.MAX_VALUE))))
+                .addGap(124, 124, 124))
+        );
+
+        jSplitPane1.setTopComponent(jPanel8);
+
+        getContentPane().add(jSplitPane1, java.awt.BorderLayout.NORTH);
+
+        jMenu9.setText("File");
+
+        jMenuItemChangePassword.setText("Change Password");
+        jMenuItemChangePassword.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemChangePasswordActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuItemChangePassword);
+
+        jMenuDirScan2.setText("Scan Disk");
+        jMenuDirScan2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuDirScanActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuDirScan2);
+
+        jMenuDirScanResume.setText("Scan Disk (resume)");
+        jMenuDirScanResume.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuDirScanResumeActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuDirScanResume);
+
+        jMenuItemShutdown.setText("Shutdown Client&Server");
+        jMenuItemShutdown.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemShutdownActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuItemShutdown);
+
+        jMenuItem11.setText("Exit Client");
+        jMenuItem11.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem11ActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuItem11);
+
+        jMenuItem7.setText("Exit Client&Server");
+        jMenuItem7.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem7ActionPerformed(evt);
+            }
+        });
+        jMenu9.add(jMenuItem7);
+
+        jMenuBar3.add(jMenu9);
+
+        jMenu10.setText("Edit");
+
+        jMenuItemPreferences.setText("Preferences");
+        jMenuItemPreferences.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem2ActionPerformed(evt);
+            }
+        });
+        jMenu10.add(jMenuItemPreferences);
+
+        jMenuItemServices.setText("Services");
+        jMenuItemServices.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemServicesActionPerformed(evt);
+            }
+        });
+        jMenu10.add(jMenuItemServices);
+
+        jMenuItem10.setText("Logs");
+        jMenuItem10.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem10ActionPerformed(evt);
+            }
+        });
+        jMenu10.add(jMenuItem10);
+
+        jMenuItemUsers.setText("User Accounts");
+        jMenuItemUsers.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemUsersActionPerformed(evt);
+            }
+        });
+        jMenu10.add(jMenuItemUsers);
+
+        jMenuItemActiveUsers.setText("ActiveUsers");
+        jMenuItemActiveUsers.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemActiveUsersActionPerformed(evt);
+            }
+        });
+        jMenu10.add(jMenuItemActiveUsers);
+
+        jMenuBar3.add(jMenu10);
+
+        jMenuTools2.setText("Tools");
+
+        jMenuItemDcm2jpeg2.setText("dcm2jpeg");
+        jMenuItemDcm2jpeg2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItemDcm2jpeg2ActionPerformed(evt);
+            }
+        });
+        jMenuTools2.add(jMenuItemDcm2jpeg2);
+
+        jMenuBar3.add(jMenuTools2);
+
+        jMenu11.setText("Skin");
+
+        jMenuItem1.setText("Business");
+        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem1ActionPerformed1(evt);
+            }
+        });
+        jMenu11.add(jMenuItem1);
+
+        jMenuItem2.setText("Business Blue Steel");
+        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem2ActionPerformed1(evt);
+            }
+        });
+        jMenu11.add(jMenuItem2);
+
+        jMenuItem3.setText("Business Black Steel");
+        jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem3ActionPerformed1(evt);
+            }
+        });
+        jMenu11.add(jMenuItem3);
+
+        jMenuItem4.setText("Creme");
+        jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem4ActionPerformed(evt);
+            }
+        });
+        jMenu11.add(jMenuItem4);
+
+        jMenuItem5.setText("Magma");
+        jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem5ActionPerformed(evt);
+            }
+        });
+        jMenu11.add(jMenuItem5);
+
+        jMenuItem6.setText("Raven");
+        jMenuItem6.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem6ActionPerformed(evt);
+            }
+        });
+        jMenu11.add(jMenuItem6);
+
+        jMenuItem8.setText("Raven Graphite Glass");
+        jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem8ActionPerformed(evt);
+            }
+        });
+        jMenu11.add(jMenuItem8);
+
+        jMenuBar3.add(jMenu11);
+
+        pluginMenu.setText("Plugins");
+        jMenuBar3.add(pluginMenu);
+
+        jMenu12.setText("Help");
+
+        jMenuItem9.setText("About");
+        jMenuItem9.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem3ActionPerformed(evt);
+            }
+        });
+        jMenu12.add(jMenuItem9);
+
+        jMenuBar3.add(jMenu12);
+
+        setJMenuBar(jMenuBar3);
+
+        getAccessibleContext().setAccessibleDescription("Dicoogle PACS Archive");
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        if (Main.isFixedClient()) {
+            jMenuItem7.doClick();
+        } else {
+            jMenuItem11.doClick();
+        }
+    }//GEN-LAST:event_formWindowClosing
+
+    private void formWindowIconified(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowIconified
+        this.setExtendedState(MainWindow.ICONIFIED);
+        this.setVisible(false);
+    }//GEN-LAST:event_formWindowIconified
+
+    private void formWindowDeiconified(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowDeiconified
+        this.setExtendedState(MainWindow.NORMAL);
+        this.setVisible(true);
+    }//GEN-LAST:event_formWindowDeiconified
+
+    private void jButtonPreferencesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPreferencesActionPerformed
+        showOptions();
+    }//GEN-LAST:event_jButtonPreferencesActionPerformed
+
+    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
+        showOptions();
+    }//GEN-LAST:event_jMenuItem2ActionPerformed
+
+    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
+
+        File toDelete = new File("pluginClasses");
+        String[] deleteArray = toDelete.list();
+        if (deleteArray != null) {
+            for (String fileName : deleteArray) {
+                File f = new File("pluginClasses/" + fileName);
+                f.delete();
+            }
+        }
+        if (clientCore.isAdmin() && AdminRefs.getInstance().unsavedSettings()) {
+            Object[] opt
+                    = {
+                        "Save", "Discard", "Cancel"
+                    };
+
+            String message = "There are unsaved Server Settings.\nDo you want to save them?";
+            int op = JOptionPane.showOptionDialog(this, message, "Unsaved Server Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+            if (op == 0) {
+                AdminRefs.getInstance().saveSettings();
+            }
+
+            if (op == 2) {
+                return;
+            }
+        }
+
+        if (ClientOptions.getInstance().unsavedSettings()) {
+            Object[] opt
+                    = {
+                        "Save", "Discard", "Cancel"
+                    };
+
+            String message = "There are unsaved Client Settings.\nDo you want to save them?";
+            int op = JOptionPane.showOptionDialog(this, message, "Unsaved Client Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+            if (op == 0) {
+                ClientOptions.getInstance().saveSettings();
+            }
+
+            if (op == 2) {
+                return;
+            }
+        }
+
+        QueryHistorySupport.getInstance().saveQueryHistory();
+
+        if (clientCore.isAdmin()) {
+            AdminRefs.getInstance().shutdownServer();
+        }
+
+        System.exit(0);
+    }//GEN-LAST:event_jMenuItem1ActionPerformed
+
+    private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed
+    }//GEN-LAST:event_jMenuItem3ActionPerformed
+
+private void jMenuDirScanActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuDirScanActionPerformed
+    scanDisk(false);
+}//GEN-LAST:event_jMenuDirScanActionPerformed
+
+    /**
+     * Do an advanced search
+     *
+     * @param evt
+     */
+    private void jButtonLogsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonLogsActionPerformed
+
+        Logs logs = Logs.getInstance();
+
+        if (logs != null) {
+            logs.setVisible(true);
+            logs.toFront();
+            //this.setEnabled(false);
+        }
+
+    }//GEN-LAST:event_jButtonLogsActionPerformed
+
+    private void jButtonServicesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonServicesActionPerformed
+        Services serv = Services.getInstance();
+        serv.setVisible(true);
+        serv.toFront();
+        //this.setEnabled(false);
+    }//GEN-LAST:event_jButtonServicesActionPerformed
+
+    private void jMenuItemServicesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemServicesActionPerformed
+
+        // invokes the event of the button jButtonServices
+        jButtonServices.doClick();
+    }//GEN-LAST:event_jMenuItemServicesActionPerformed
+
+    private void jMenuItem1ActionPerformed1(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed1
+        SubstanceLookAndFeel.setSkin(new BusinessSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem1ActionPerformed1
+
+    private void jMenuItem2ActionPerformed1(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed1
+        SubstanceLookAndFeel.setSkin(new BusinessBlueSteelSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem2ActionPerformed1
+
+    private void jMenuItem3ActionPerformed1(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed1
+        SubstanceLookAndFeel.setSkin(new BusinessBlackSteelSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem3ActionPerformed1
+
+    private void jMenuItem4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem4ActionPerformed
+        SubstanceLookAndFeel.setSkin(new CremeSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem4ActionPerformed
+
+    private void jMenuItem5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem5ActionPerformed
+        SubstanceLookAndFeel.setSkin(new MagmaSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem5ActionPerformed
+
+    private void jMenuItem6ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem6ActionPerformed
+        SubstanceLookAndFeel.setSkin(new RavenSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem6ActionPerformed
+
+    private void jMenuItem8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem8ActionPerformed
+        SubstanceLookAndFeel.setSkin(new RavenGraphiteGlassSkin());
+        repaint();
+    }//GEN-LAST:event_jMenuItem8ActionPerformed
+
+    private void jMenuItem10ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem10ActionPerformed
+
+        // invokes the event of the button jButtonLogs
+        jButtonLogs.doClick();
+    }//GEN-LAST:event_jMenuItem10ActionPerformed
+
+    private void jButtonPeersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPeersActionPerformed
+        try {
+            List<NetworkMember> peerList = UserRefs.getInstance().getSearch().getPeerList();
+
+            String peerNames = "These are the P2P peers that are connected:";
+            if (peerList.size() == 0) {
+                peerNames = "No peers connected!";
+            }
+
+            for (NetworkMember s : peerList) {
+                peerNames += "\n" + s.getPeerName() + " : " + s.getPluginName();
+            }
+
+            JOptionPane.showMessageDialog(this, peerNames, "P2P Peers", JOptionPane.INFORMATION_MESSAGE);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonPeersActionPerformed
+
+    private void jMenuItemUsersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemUsersActionPerformed
+        UsersManager usersManager = UsersManager.getInstance();
+
+        if (usersManager != null) {
+            usersManager.setVisible(true);
+            usersManager.toFront();
+            //this.setEnabled(false);
+        }
+    }//GEN-LAST:event_jMenuItemUsersActionPerformed
+
+    public void updateP2PThumbnail(SearchResult result) {
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode) getjTreeResults().getLastSelectedPathComponent();
+        if (node == null) {
+            return;
+        }
+
+        Object nodeInfo = null;
+        DefaultMutableTreeNode nodeLeaf = null;
+
+        if (node.getLevel() == 4 || (node.isLeaf() && node.getLevel() > 1)) {
+            Object nodeInfoLeaf = null;
+
+            if (node.getLevel() == 4) {
+                nodeLeaf = node.getFirstLeaf();
+                nodeInfoLeaf = nodeLeaf.getUserObject();
+            } else {
+                // Leaf
+                nodeInfo = node.getUserObject();
+                nodeLeaf = node;
+                nodeInfoLeaf = nodeInfo;
+            }
+
+            //SearchResult r = (SearchResult) nodeInfoLeaf;
+            if (nodeInfoLeaf == result) {
+                showThumbnail((String) result.getExtraData().get("Thumbnail"));
+            }
+        }
+
+    }
+
+    private void jMenuItemChangePasswordActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemChangePasswordActionPerformed
+        ChangePassword changePassword = ChangePassword.getInstance();
+
+        if (changePassword != null) {
+            changePassword.setVisible(true);
+            changePassword.toFront();
+        }
+    }//GEN-LAST:event_jMenuItemChangePasswordActionPerformed
+
+    private void jMenuItemActiveUsersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemActiveUsersActionPerformed
+        ActiveSessions activeSessions = ActiveSessions.getInstance();
+
+        if (activeSessions != null) {
+            activeSessions.setVisible(true);
+            activeSessions.toFront();
+            //this.setEnabled(false);
+        }
+    }//GEN-LAST:event_jMenuItemActiveUsersActionPerformed
+
+    private void jButtonClientPreferencesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonClientPreferencesActionPerformed
+        ClientOptions cliOptions = ClientOptions.getInstance();
+
+        if (cliOptions != null) {
+            cliOptions.setVisible(true);
+            cliOptions.toFront();
+        }
+    }//GEN-LAST:event_jButtonClientPreferencesActionPerformed
+
+    @SuppressWarnings("empty-statement")
+    private void jMenuItemShutdownActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemShutdownActionPerformed
+        Object[] opt
+                = {
+                    "Yes", "No"
+                };
+
+        String message = "Are you shure you want to shutdown the server?";
+        int op = JOptionPane.showOptionDialog(this, message, "Shut down Server", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[1]);
+
+        if (op == 0) {
+            //Logout from GUI Server
+            if (clientCore.isAdmin()) {
+
+                if (AdminRefs.getInstance().unsavedSettings()) {
+                    Object[] opt1
+                            = {
+                                "Save", "Discard"
+                            };
+
+                    message = "There are unsaved Server Settings.\nDo you want to save them?";
+                    op = JOptionPane.showOptionDialog(this, message, "Unsaved Server Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt1, opt1[0]);
+
+                    if (op == 0) {
+                        AdminRefs.getInstance().saveSettings();
+                    }
+
+                }
+            }
+
+            if (clientCore.isUser()) {
+                if (ClientOptions.getInstance().unsavedSettings()) {
+                    Object[] opt2
+                            = {
+                                "Save",
+                                "Discard"
+                            };
+
+                    message = "There are unsaved Client Settings.\nDo you want to save them?";
+                    op = JOptionPane.showOptionDialog(this, message, "Unsaved Client Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt2, opt2[0]);
+
+                    if (op == 0) {
+                        ClientOptions.getInstance().saveSettings();
+                    }
+                }
+            }
+
+            QueryHistorySupport.getInstance().saveQueryHistory();
+
+            if (clientCore.isAdmin()) {
+                AdminRefs.getInstance().shutdownServer();
+            }
+
+            System.exit(0);
+        }
+    }//GEN-LAST:event_jMenuItemShutdownActionPerformed
+
+    private void jMenuItemDcm2jpeg2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItemDcm2jpeg2ActionPerformed
+        dcm2JPEG(0);
+    }//GEN-LAST:event_jMenuItemDcm2jpeg2ActionPerformed
+
+    private void jMenuItem11ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem11ActionPerformed
+        //Logout from GUI Server
+        try {
+            if (clientCore.isAdmin() && AdminRefs.getInstance().unsavedSettings()) {
+                Object[] opt
+                        = {
+                            "Save", "Discard", "Cancel"
+                        };
+
+                String message = "There are unsaved Server Settings.\nDo you want to save them?";
+                int op = JOptionPane.showOptionDialog(this, message, "Unsaved Server Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+                if (op == 0) {
+                    AdminRefs.getInstance().saveSettings();
+                }
+
+                if (op == 2) {
+                    return;
+                }
+            }
+
+            if (clientCore.isUser() && ClientOptions.getInstance().unsavedSettings()) {
+                Object[] opt
+                        = {
+                            "Save", "Discard", "Cancel"
+                        };
+
+                String message = "There are unsaved Client Settings.\nDo you want to save them?";
+                int op = JOptionPane.showOptionDialog(this, message, "Unsaved Client Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+                if (op == 0) {
+                    ClientOptions.getInstance().saveSettings();
+                }
+
+                if (op == 2) {
+                    return;
+                }
+            }
+
+            if (clientCore.isAdmin()) {
+                AdminRefs.getInstance().logout();
+            }
+
+            searchTree.unexportSearchSignal();
+            clientCore.getUser().logout();
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+        File toDelete = new File("pluginClasses");
+        String[] deleteArray = toDelete.list();
+        if (deleteArray != null) {
+            for (String fileName : deleteArray) {
+                File f = new File("pluginClasses/" + fileName);
+                f.delete();
+            }
+        }
+        QueryHistorySupport.getInstance().saveQueryHistory();
+
+        if (Main.isFixedClient()) {
+            clientCore.stopKeepAlives();
+            this.dispose();
+        } else {
+            System.exit(0);
+        }
+    }//GEN-LAST:event_jMenuItem11ActionPerformed
+
+private void jMenuItem7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem7ActionPerformed
+    File toDelete = new File("pluginClasses");
+    String[] deleteArray = toDelete.list();
+    if (deleteArray != null) {
+        for (String fileName : deleteArray) {
+            File f = new File("pluginClasses/" + fileName);
+            f.delete();
+        }
+    }
+    if (clientCore.isAdmin() && AdminRefs.getInstance().unsavedSettings()) {
+        Object[] opt
+                = {
+                    "Save", "Discard", "Cancel"
+                };
+
+        String message = "There are unsaved Server Settings.\nDo you want to save them?";
+        int op = JOptionPane.showOptionDialog(this, message, "Unsaved Server Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+        if (op == 0) {
+            AdminRefs.getInstance().saveSettings();
+        }
+
+        if (op == 2) {
+            return;
+        }
+    }
+
+    if (ClientOptions.getInstance().unsavedSettings()) {
+        Object[] opt
+                = {
+                    "Save", "Discard", "Cancel"
+                };
+
+        String message = "There are unsaved Client Settings.\nDo you want to save them?";
+        int op = JOptionPane.showOptionDialog(this, message, "Unsaved Client Settings", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, opt, opt[2]);
+
+        if (op == 0) {
+            ClientOptions.getInstance().saveSettings();
+        }
+
+        if (op == 2) {
+            return;
+        }
+    }
+
+    QueryHistorySupport.getInstance().saveQueryHistory();
+
+    if (clientCore.isAdmin()) {
+        AdminRefs.getInstance().shutdownServer();
+    }
+
+    System.exit(0);
+}//GEN-LAST:event_jMenuItem7ActionPerformed
+
+private void jTreeResultsKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTreeResultsKeyReleased
+    if (KeyEvent.VK_DELETE == evt.getKeyCode() && clientCore.isAdmin()) {
+        ArrayList<String> files = getSelectedLocalFiles();
+
+        if (files != null && !files.isEmpty()) {
+            try {
+                Object[] opt
+                        = {
+                            "Remove and Delete", "Remove", "Cancel"
+                        };
+                String message = "Are you sure you want to remove these files from Index Engine?";
+
+                int op = JOptionPane.showOptionDialog(this, message, "Remove Files", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, opt, opt[2]);
+
+                if (op == 0) {
+                    AdminRefs.getInstance().getIndexOptions().removeFilesFromIndexer(files, true);
+                }
+                if (op == 1) {
+                    AdminRefs.getInstance().getIndexOptions().removeFilesFromIndexer(files, false);
+                }
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+            }
+        }
+    }
+}//GEN-LAST:event_jTreeResultsKeyReleased
+
+    /*
+     * This need some serious rewritting
+     * alot of cruft
+     */
+private void jTreeResultsValueChanged(javax.swing.event.TreeSelectionEvent evt) {//GEN-FIRST:event_jTreeResultsValueChanged
+
+    /*
+     DefaultMutableTreeNode node = (DefaultMutableTreeNode) getjTreeResults().getLastSelectedPathComponent();
+     if (node == null){
+     return;
+     }
+     this.jButtonDownload.setEnabled(false);
+     Object nodeInfo = null;
+     DefaultMutableTreeNode nodeLeaf = null;
+
+
+     if (node.getLevel() == 4 || (node.isLeaf() && node.getLevel() > 1)){
+     Object nodeInfoLeaf = null;
+
+     if (node.getLevel() == 4){
+     nodeLeaf = node.getFirstLeaf();
+     nodeInfoLeaf = nodeLeaf.getUserObject();
+     }
+     else{
+     // Leaf
+     nodeInfo = node.getUserObject();
+     nodeLeaf = node;
+     nodeInfoLeaf = nodeInfo;
+     }
+
+     SearchResult r = (SearchResult) nodeInfoLeaf;
+
+     //HashMap extras = r.getExtraData();
+     //String thumb = (String) extras.get("Thumbnail");
+
+     //System.out.println("Filename: " + r.getFileName());
+     //System.out.println("FileHash: " + r.getFileHash());
+     */
+    /*if (thumb != null){
+     showThumbnail(thumb);
+     }
+     else if (!SearchResult.class.isInstance(nodeInfoLeaf) && SearchResult.class.isInstance(nodeInfoLeaf)){
+     SearchResult res = searchTree.searchThumbnail(r.getURI(), "filehash");//was r.getFileHash, should be placed on extradata
+
+     if (res != null){
+     HashMap extras2 = res.getExtraData();
+
+     if (extras2 != null){
+     thumb = (String) extras2.get("Thumbnail");
+
+     if (thumb != null){
+     extras.put("Thumbnail", thumb); // put the thumbnail in the original SearchResult
+
+     showThumbnail(thumb);
+     }
+     else{
+     cleanThumbnails();
+     }
+     }
+     }
+     //TODO
+     //this must be removed! we must not care where the search comes from
+     }
+     else if (SearchResult.class.isInstance(nodeInfoLeaf)){
+     searchTree.searchP2PThumbnail(r);
+     cleanThumbnails();
+     }
+     else{
+     cleanThumbnails();
+     }*/
+    /*  }
+     else{
+     cleanThumbnails();
+     }
+
+     //Controll the enable buttons
+     if (node.isLeaf())
+     {
+     jButtonDump.setEnabled(true);
+     IPluginControllerUser plugins = null;
+     try
+     {
+     plugins = this.clientCore.getUser().getPluginController();
+            
+     //dafuq is this?
+     if ((SearchResult) nodeInfo==null)
+     {
+                
+            
+     }
+     */
+            //TODO: fix this!
+            /*if (!plugins.isLocalPlugin(((SearchResult) nodeInfo).getPluginName()))
+     {
+     jButtonDownload.setEnabled(true);
+     jButtonSend.setEnabled(false);
+     } else
+     {*/
+    /*          jButtonSend.setEnabled(true);
+     jButtonView.setEnabled(true);
+     //}
+     }
+     catch (RemoteException ex){
+     Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
+     }
+     }
+     else{
+     jButtonDump.setEnabled(false);
+     jButtonDownload.setEnabled(false);
+     jButtonView.setEnabled(false);
+
+     jButtonSend.setEnabled(true);
+     }*/
+}//GEN-LAST:event_jTreeResultsValueChanged
+
+private void jTreeResultsTreeExpanded(javax.swing.event.TreeExpansionEvent evt) {//GEN-FIRST:event_jTreeResultsTreeExpanded
+    //searchTree.completeTree(evt);
+}//GEN-LAST:event_jTreeResultsTreeExpanded
+
+private void jTreeResultsMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTreeResultsMouseClicked
+    //Double Click -> Show MetaData
+    if (evt.getClickCount() == 2) {
+        showMetaData();
+    }
+
+    if (evt.getButton() == MouseEvent.BUTTON3) {
+        popupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
+        popupMenu.list();
+    }
+}//GEN-LAST:event_jTreeResultsMouseClicked
+
+private void jButtonExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonExportActionPerformed
+    if (jTreeResults.getModel().getChildCount(jTreeResults.getModel().getRoot()) == 0) {
+        JOptionPane.showMessageDialog(this, "You can't export information without search results.", "Lack of Search Results", JOptionPane.INFORMATION_MESSAGE);
+        return;
+    }
+
+    ExportData ed;
+
+    HashMap<String, Boolean> plugins = new HashMap<String, Boolean>();
+    for (JCheckBox box : this.ranges) {
+        plugins.put(box.getText(), box.isSelected());
+    }
+    if (!lastQueryAdvanced) {
+
+        ed = new ExportData(lastQueryExecuted, lastQueryKeywords, plugins);
+    } else {
+        ed = new ExportData(lastQueryExecuted, true, plugins);
+    }
+
+    ed.setVisible(true);
+    ed.toFront();
+}//GEN-LAST:event_jButtonExportActionPerformed
+
+//what a nice and descriptive name... I don't know what it does,
+//so there is a big chance of having broke something
+private void jButtonViewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonViewActionPerformed
+    DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTreeResults.getLastSelectedPathComponent();
+    if (node == null) {
+        return;
+    }
+
+    Object nodeInfo = node.getUserObject();
+    // int selected = this.jList1.getSelectedIndex();
+    if (node.isLeaf()) {
+        if (SearchResult.class.isInstance(nodeInfo)) {
+            SearchResult tmp = (SearchResult) nodeInfo;
+
+            //Why are we caring about this?
+            if (clientCore.isLocalServer()) {
+
+                File f = new File(tmp.getURI());
+                if (!f.exists()) {
+                    JOptionPane.showMessageDialog(this, "Dicoogle can't open this file, because this file does not exists in your file system. Try Dump button instead View!", "Error opening the file", JOptionPane.ERROR_MESSAGE);
+                    return;
+                }
+
+                if (ClientSettings.getInstance().getExtV() == null
+                        || ClientSettings.getInstance().getExtV().equals("")) {
+
+                    try {
+                        Desktop.getDesktop().open(new File(tmp.getURI()));
+
+                    } catch (IOException ex) {
+                        //oh dear
+                        String folder = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf('/'));
+
+                        try {
+                            Desktop.getDesktop().open(new File(folder));
+
+                        } catch (IOException ex1) {
+                            JOptionPane.showMessageDialog(this, "Dicoogle can't open this file!", "Error opening the file", JOptionPane.ERROR_MESSAGE);
+                        }
+                    }
+                } else {
+                    try {
+                        //I changed something, no ideia do i have on what goes around here
+                        ProcessBuilder pb = new ProcessBuilder(ClientSettings.getInstance().getExtV(), tmp.getURI().toString());
+                        pb.start();
+
+                        //Runtime.getRuntime().exec(ClientSettings.getInstance().getExtV() + " "+path);
+                    } catch (IOException ex) {
+                        //ex.printStackTrace();
+
+                        String folder = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf('/'));
+
+                        try {
+                            Desktop.getDesktop().open(new File(folder));
+
+                        } catch (IOException ex1) {
+                            JOptionPane.showMessageDialog(this, "Dicoogle can't open this file!", "Error opening the file", JOptionPane.ERROR_MESSAGE);
+                        }
+                    }
+                }
+            } else {
+                try {
+                    SimpleEntry<RemoteFile, Integer> entry = UserRefs.getInstance().getSearch().downloadFile(tmp);
+
+                    TransferStatus ts = new TransferStatus(entry.getKey());
+
+                    FileReceiver receiver = new FileReceiver(entry.getKey(), clientCore.getServerAddress(), entry.getValue(), ts);
+
+                    Thread tReceiver = receiver;
+                    tReceiver.start();
+
+                    ts.setVisible(true);
+                    ts.toFront();
+
+                } catch (RemoteException ex) {
+                    LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+                } catch (IOException ex) {
+                    LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+                }
+            }
+        }
+    }
+}//GEN-LAST:event_jButtonViewActionPerformed
+
+private void jButtonDownloadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDownloadActionPerformed
+
+    DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTreeResults.getLastSelectedPathComponent();
+    if (node == null) {
+        return;
+    }
+
+    Object nodeInfo = node.getUserObject();
+
+    if (node.isLeaf() && SearchResult.class.isInstance(nodeInfo)) {
+        try {
+            SearchResult temp = (SearchResult) nodeInfo;
+            UserRefs.getInstance().getSearch().RequestP2PFile(temp);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(MainWindow.class).error(ex.getMessage(), ex);
+        }
+    }
+}//GEN-LAST:event_jButtonDownloadActionPerformed
+
+private void jButtonDumpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDumpActionPerformed
+    showMetaData();
+}//GEN-LAST:event_jButtonDumpActionPerformed
+
+private void jButtonSendActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSendActionPerformed
+    ArrayList<String> files = getSelectedLocalFiles();
+
+    if (files != null && !files.isEmpty()) {
+        DicomSend d = new DicomSend(files);
+
+        d.setVisible(true);
+        d.toFront();
+    } else {
+        JOptionPane.showMessageDialog(this, "Please Select Local Files to send.", "Select files", JOptionPane.INFORMATION_MESSAGE);
+    }
+}//GEN-LAST:event_jButtonSendActionPerformed
+
+private void jButtonQueryHistoryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonQueryHistoryActionPerformed
+    QueryHistory QH = QueryHistory.getInstance();
+    QH.setVisible(true);
+    QH.toFront();
+    QH.setJTextFieldQuery(jTextFieldQuery, jCheckBoxKeywords);
+}//GEN-LAST:event_jButtonQueryHistoryActionPerformed
+
+private void SearchTipsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SearchTipsActionPerformed
+    SearchTips tip = new SearchTips(this.jTextFieldQuery);
+    tip.setVisible(true);
+    tip.toFront();
+}//GEN-LAST:event_SearchTipsActionPerformed
+
+    enum QUERY_STATE {
+
+        READY_TO_SEARCH, WAITING_FOR_RESULTS
+    }
+    private QUERY_STATE state = QUERY_STATE.READY_TO_SEARCH;
+    private boolean basicSearch = true;
+
+    public void search() {
+
+        LoggerFactory.getLogger(MainWindow.class).debug("State: {}", state);
+        if (state == QUERY_STATE.WAITING_FOR_RESULTS) {
+
+            LoggerFactory.getLogger(MainWindow.class).debug("Pruning query");
+
+            pruneQuery();
+            return;
+        }
+
+        this.jButtonDownload.setEnabled(false);
+        lastQueryExecuted = jTextFieldQuery.getText();
+        lastQueryKeywords = jCheckBoxKeywords.isSelected();
+        lastQueryAdvanced = false;
+        HashMap<String, Boolean> plugins = new HashMap<String, Boolean>();
+        boolean isSelectedPlugins = false;
+        for (JCheckBox box : this.ranges) {
+            plugins.put(box.getText(), box.isSelected());
+            isSelectedPlugins = isSelectedPlugins || box.isSelected();
+        }
+        if (!isSelectedPlugins) {
+            JOptionPane.showMessageDialog(this, "Please select a source to search", "Missing data source", JOptionPane.INFORMATION_MESSAGE);
+        } else {
+            basicSearch = true;
+            searchTree.search(lastQueryExecuted, lastQueryKeywords, plugins);
+            state = QUERY_STATE.WAITING_FOR_RESULTS;
+            jButtonSearch.setText("Cancel");
+            cleanThumbnails();
+            QueryHistorySupport.getInstance().saveQueryHistory();
+        }
+
+    }
+
+    public void pruneQuery() {
+        System.out.println("Prune here");
+        searchTree.pruneQuery(null);
+        state = QUERY_STATE.READY_TO_SEARCH;
+        jButtonSearch.setText("Search");
+    }
+
+    public void finishQuery() {
+        //System.out.println("The query is done");
+        jButtonSearch.setText("Search");
+
+        state = QUERY_STATE.READY_TO_SEARCH;
+    }
+
+    /*
+     * Updates the tree view using the query results.
+     * 
+     * todo: the tree is not a parameter to the method, as such it has state. make the tree to be updated an argument
+     */
+    private void updateSearchView(Iterable<SearchResult> searchResultIterator) {
+
+        HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> tree;//omfgIHateYou;
+        tree = SearchResult.toTree(searchResultIterator);
+
+        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Search Results");
+
+        for (String patientName : tree.keySet()) {
+            DefaultMutableTreeNode patientMap = new DefaultMutableTreeNode(patientName);
+            root.add(patientMap);
+
+            for (String studyUID : tree.get(patientName).keySet()) {
+                DefaultMutableTreeNode studyMap = new DefaultMutableTreeNode(studyUID);
+                patientMap.add(studyMap);
+
+                for (String seriesUID : tree.get(patientName).get(studyUID).keySet()) {
+                    DefaultMutableTreeNode seriesMap = new DefaultMutableTreeNode(seriesUID);
+                    studyMap.add(seriesMap);
+
+                    for (SearchResult r : tree.get(patientName).get(studyUID).get(seriesUID).values()) {
+                        DefaultMutableTreeNode images = new DefaultMutableTreeNode(r);
+                        seriesMap.add(images);
+                    }
+                }
+            }
+        }
+        DefaultTreeModel treeModel = new DefaultTreeModel(root);
+        jTreeResults.setModel(treeModel);
+    }
+
+private void jButtonSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSearchActionPerformed
+    String query = jTextFieldQuery.getText();
+
+    //prepares the info we are interested in
+    HashMap<String, Object> options = new HashMap<>();
+    options.put("PatientName", null);
+    options.put("PatientID", null);
+    options.put("StudyInstanceUID", null);
+    options.put("SeriesInstanceUID", null);
+    options.put("SOPInstanceUID", null);
+
+    //runs the query task asynchronously
+    List<String> providers = new ArrayList<>();
+    for (JCheckBox chkBox : this.ranges) {
+        if (chkBox.isSelected()) {
+            providers.add(chkBox.getText());
+            System.out.println("Selected: " + chkBox.getText());
+        }
+    }
+
+    JointQueryTask task = new JointQueryTask() {
+
+        @Override
+        public void onReceive(Task<Iterable<SearchResult>> e) {
+            // TODO Auto-generated method stub
+            try {
+                updateSearchView(e.get());
+            } catch (InterruptedException | ExecutionException e1) {
+                // TODO Auto-generated catch block
+                e1.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onCompletion() {
+			// TODO Auto-generated method stub
+
+        }
+    };
+
+    task = PluginController.getInstance().query(task, providers, query, options);
+
+
+}//GEN-LAST:event_jButtonSearchActionPerformed
+
+
+private void DateRangeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DateRangeActionPerformed
+    if (ExactDate.isSelected()) {
+        ExactDate.setSelected(false);
+    }
+    StudyDateRangeInitialBoundaryActivation.setEnabled(true);
+    StudyDateRangeTerminalBoundaryActivation.setEnabled(true);
+    StudyDateRangeInitialBoundary.setEnabled(false);
+    StudyDateRangeTerminalBoundary.setEnabled(false);
+    StudyDate.setEnabled(false);
+}//GEN-LAST:event_DateRangeActionPerformed
+
+private void ExactDateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ExactDateActionPerformed
+    if (DateRange.isSelected()) {
+        DateRange.setSelected(false);
+    }
+    StudyDateRangeInitialBoundaryActivation.setEnabled(false);
+    StudyDateRangeTerminalBoundaryActivation.setEnabled(false);
+    StudyDateRangeInitialBoundary.setEnabled(false);
+    StudyDateRangeTerminalBoundary.setEnabled(false);
+    StudyDate.setEnabled(true);
+}//GEN-LAST:event_ExactDateActionPerformed
+
+private void StudyDateRangeTerminalBoundaryActivationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_StudyDateRangeTerminalBoundaryActivationActionPerformed
+    if (StudyDateRangeTerminalBoundaryActivation.isSelected()) {
+        StudyDateRangeTerminalBoundary.setEnabled(true);
+    } else {
+        StudyDateRangeTerminalBoundary.setEnabled(false);
+    }
+}//GEN-LAST:event_StudyDateRangeTerminalBoundaryActivationActionPerformed
+
+private void StudyDateRangeInitialBoundaryActivationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_StudyDateRangeInitialBoundaryActivationActionPerformed
+    if (StudyDateRangeInitialBoundaryActivation.isSelected()) {
+        StudyDateRangeInitialBoundary.setEnabled(true);
+    } else {
+        StudyDateRangeInitialBoundary.setEnabled(false);
+    }
+}//GEN-LAST:event_StudyDateRangeInitialBoundaryActivationActionPerformed
+
+private void ResetFieldsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ResetFieldsActionPerformed
+
+    ModalSelectNone.setSelected(false);
+    ModalSelectAll.setSelected(true);
+    ModalCR.setSelected(true);
+    ModalCT.setSelected(true);
+    ModalDX.setSelected(true);
+    ModalES.setSelected(true);
+    ModalMG.setSelected(true);
+    ModalMR.setSelected(true);
+    ModalNM.setSelected(true);
+    ModalOT.setSelected(true);
+    ModalPT.setSelected(true);
+    ModalRF.setSelected(true);
+    ModalSC.setSelected(true);
+    ModalUS.setSelected(true);
+    ModalXA.setSelected(true);
+
+    StudyDateRangeInitialBoundary.setEnabled(false);
+    StudyDateRangeTerminalBoundary.setEnabled(false);
+
+    DateRange.setSelected(false);
+    ExactDate.setSelected(true);
+
+    StudyDateRangeInitialBoundaryActivation.setEnabled(false);
+    StudyDateRangeTerminalBoundaryActivation.setEnabled(false);
+    StudyDateRangeInitialBoundary.setEnabled(false);
+    StudyDateRangeTerminalBoundary.setEnabled(false);
+    StudyDate.setEnabled(true);
+    PatientName.setText("(All patients)");
+    PatientID.setText("(All IDs)");
+    PatientGender.setSelectedIndex(0);
+    InstitutionName.setText("(All institutions)");
+    Physician.setText("(All physicians)");
+    OperatorName.setText("(All operators)");
+    StudyDate.setText("(All dates)");
+    StudyDateRangeInitialBoundary.setText("(Beginning)");
+    StudyDateRangeTerminalBoundary.setText("(Today)");
+}//GEN-LAST:event_ResetFieldsActionPerformed
+
+private void AdvancedSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_AdvancedSearchButtonActionPerformed
+    lastQueryExecuted = getAdvancedQuery();
+    lastQueryAdvanced = true;
+    HashMap<String, Boolean> plugins = new HashMap<String, Boolean>();
+    for (JCheckBox box : this.ranges) {
+        plugins.put(box.getText(), box.isSelected());
+    }
+    searchTree.search(lastQueryExecuted, true, plugins);
+
+    cleanThumbnails();
+}//GEN-LAST:event_AdvancedSearchButtonActionPerformed
+
+private void ModalSelectNoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalSelectNoneActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+    ModalCR.setSelected(false);
+    ModalCT.setSelected(false);
+    ModalDX.setSelected(false);
+    ModalES.setSelected(false);
+    ModalMG.setSelected(false);
+    ModalMR.setSelected(false);
+    ModalNM.setSelected(false);
+    ModalOT.setSelected(false);
+    ModalPT.setSelected(false);
+    ModalRF.setSelected(false);
+    ModalSC.setSelected(false);
+    ModalUS.setSelected(false);
+    ModalXA.setSelected(false);
+}//GEN-LAST:event_ModalSelectNoneActionPerformed
+
+private void ModalSelectAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalSelectAllActionPerformed
+    ModalSelectNone.setSelected(false);
+    ModalSelectAll.setSelected(true);
+    ModalCR.setSelected(true);
+    ModalCT.setSelected(true);
+    ModalDX.setSelected(true);
+    ModalES.setSelected(true);
+    ModalMG.setSelected(true);
+    ModalMR.setSelected(true);
+    ModalNM.setSelected(true);
+    ModalOT.setSelected(true);
+    ModalPT.setSelected(true);
+    ModalRF.setSelected(true);
+    ModalSC.setSelected(true);
+    ModalUS.setSelected(true);
+    ModalXA.setSelected(true);
+}//GEN-LAST:event_ModalSelectAllActionPerformed
+
+private void ModalXAActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalXAActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalXAActionPerformed
+
+private void ModalUSActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalUSActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalUSActionPerformed
+
+private void ModalOTActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalOTActionPerformed
+    ModalSelectAll.setSelected(false);
+    ModalSelectNone.setSelected(true);
+}//GEN-LAST:event_ModalOTActionPerformed
+
+private void ModalESActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalESActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalESActionPerformed
+
+private void ModalSCActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalSCActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalSCActionPerformed
+
+private void ModalNMActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalNMActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalNMActionPerformed
+
+private void ModalDXActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalDXActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalDXActionPerformed
+
+private void ModalRFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalRFActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalRFActionPerformed
+
+private void ModalMRActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalMRActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalMRActionPerformed
+
+private void ModalCTActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalCTActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalCTActionPerformed
+
+private void ModalPTActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalPTActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalPTActionPerformed
+
+private void ModalMGActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalMGActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalMGActionPerformed
+
+private void ModalCRActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ModalCRActionPerformed
+    ModalSelectNone.setSelected(true);
+    ModalSelectAll.setSelected(false);
+}//GEN-LAST:event_ModalCRActionPerformed
+
+private void SelectDefaultSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SelectDefaultSearchActionPerformed
+    SelectAdvancedSearch.setSelected(false);
+    SelectDefaultSearch.setSelected(true);
+    jPanel1.setVisible(true);
+    jPanel2.setVisible(false);
+}//GEN-LAST:event_SelectDefaultSearchActionPerformed
+
+private void SelectAdvancedSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SelectAdvancedSearchActionPerformed
+    SelectDefaultSearch.setSelected(false);
+    SelectAdvancedSearch.setSelected(true);
+    jPanel1.setVisible(false);
+    jPanel2.setVisible(true);
+}//GEN-LAST:event_SelectAdvancedSearchActionPerformed
+
+    private void scanDisk(boolean resume) {
+
+        if (!clientCore.isLocalServer()) {
+            class Action1 extends FileAction {
+
+                private boolean resume = false;
+
+                public void setResume(boolean resume) {
+
+                    this.resume = resume;
+                }
+
+                @Override
+                public void setFileChoosed(String filePath) {
+                    AdminRefs.getInstance().index(filePath, resume);
+
+                    /*TaskList tasks = TaskList.getInstance();
+                     tasks.setVisible(true);
+                     tasks.toFront();*/
+                }
+            }
+
+            Action1 action = new Action1();
+            action.setResume(resume);
+
+            RemoteFileChooser chooser = new RemoteFileChooser(AdminRefs.getInstance().getRFS(), AdminRefs.getInstance().getDefaultFilePath(), action);
+
+            chooser.setTitle("Dicoogle Scan Directory");
+            chooser.setFileSelectionMode(RemoteFileChooser.DIRECTORIES_ONLY);
+
+            chooser.setVisible(true);
+            // TODO:  put showTaskList = false; -- somewhere...
+
+        } else {
+            JFileChooser chooser = new JFileChooser();
+            chooser.setCurrentDirectory(new java.io.File(AdminRefs.getInstance().getDefaultFilePath()));
+            chooser.setDialogTitle("Dicoogle Scan Directory");
+            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+            chooser.setAcceptAllFileFilterUsed(false);
+
+            if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
+                AdminRefs.getInstance().index(chooser.getSelectedFile().toString(), resume);
+
+                /*TaskList tasks = TaskList.getInstance();
+                 tasks.setVisible(true);
+                 tasks.toFront();*/
+            }
+
+        }
+
+    }
+
+private void jMenuDirScanResumeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuDirScanResumeActionPerformed
+
+    scanDisk(true);
+
+}//GEN-LAST:event_jMenuDirScanResumeActionPerformed
+
+private void jTextFieldQueryKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextFieldQueryKeyPressed
+
+    if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
+        search();
+    }
+
+
+}//GEN-LAST:event_jTextFieldQueryKeyPressed
+
+    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
+
+        if (Main.isFixedClient()) {
+
+            PluginController PController = PluginController.getInstance();
+            //TODO: DELETED
+            //PController.initGUI();
+        }
+
+    }//GEN-LAST:event_formWindowOpened
+
+    private void jTextFieldQueryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextFieldQueryActionPerformed
+        // TODO add your handling code here:
+    }//GEN-LAST:event_jTextFieldQueryActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton AdvancedSearchButton;
+    private javax.swing.JRadioButton DateRange;
+    private javax.swing.JRadioButton ExactDate;
+    private javax.swing.JTextField InstitutionName;
+    private javax.swing.JCheckBox ModalCR;
+    private javax.swing.JCheckBox ModalCT;
+    private javax.swing.JCheckBox ModalDX;
+    private javax.swing.JCheckBox ModalES;
+    private javax.swing.JCheckBox ModalMG;
+    private javax.swing.JCheckBox ModalMR;
+    private javax.swing.JCheckBox ModalNM;
+    private javax.swing.JCheckBox ModalOT;
+    private javax.swing.JCheckBox ModalPT;
+    private javax.swing.JCheckBox ModalRF;
+    private javax.swing.JCheckBox ModalSC;
+    private javax.swing.JRadioButton ModalSelectAll;
+    private javax.swing.JRadioButton ModalSelectNone;
+    private javax.swing.JCheckBox ModalUS;
+    private javax.swing.JCheckBox ModalXA;
+    private javax.swing.JTextField OperatorName;
+    private javax.swing.JComboBox PatientGender;
+    private javax.swing.JTextField PatientID;
+    private javax.swing.JTextField PatientName;
+    private javax.swing.JTextField Physician;
+    private javax.swing.JButton ResetFields;
+    private javax.swing.JButton SearchTips;
+    private javax.swing.JRadioButton SelectAdvancedSearch;
+    private javax.swing.JRadioButton SelectDefaultSearch;
+    private javax.swing.JTextField StudyDate;
+    private javax.swing.JTextField StudyDateRangeInitialBoundary;
+    private javax.swing.JCheckBox StudyDateRangeInitialBoundaryActivation;
+    private javax.swing.JTextField StudyDateRangeTerminalBoundary;
+    private javax.swing.JCheckBox StudyDateRangeTerminalBoundaryActivation;
+    private javax.swing.JButton jButtonClientPreferences;
+    private javax.swing.JButton jButtonDownload;
+    private javax.swing.JButton jButtonDump;
+    private javax.swing.JButton jButtonExport;
+    private javax.swing.JButton jButtonLogs;
+    private javax.swing.JButton jButtonPeers;
+    private javax.swing.JButton jButtonPreferences;
+    private javax.swing.JButton jButtonQueryHistory;
+    private javax.swing.JButton jButtonSearch;
+    private javax.swing.JButton jButtonSend;
+    private javax.swing.JButton jButtonServices;
+    private javax.swing.JButton jButtonView;
+    private javax.swing.JCheckBox jCheckBoxKeywords;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel10;
+    private javax.swing.JLabel jLabel11;
+    private javax.swing.JLabel jLabel12;
+    private javax.swing.JLabel jLabel13;
+    private javax.swing.JLabel jLabel14;
+    private javax.swing.JLabel jLabel15;
+    private javax.swing.JLabel jLabel16;
+    private javax.swing.JLabel jLabel17;
+    private javax.swing.JLabel jLabel19;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel20;
+    private javax.swing.JLabel jLabel22;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel7;
+    private javax.swing.JLabel jLabel8;
+    private javax.swing.JLabel jLabel9;
+    private javax.swing.JLabel jLabelResults;
+    private javax.swing.JLabel jLabelTime;
+    private javax.swing.JMenu jMenu10;
+    private javax.swing.JMenu jMenu11;
+    private javax.swing.JMenu jMenu12;
+    private javax.swing.JMenu jMenu9;
+    private javax.swing.JMenuBar jMenuBar3;
+    private javax.swing.JMenuItem jMenuDirScan2;
+    private javax.swing.JMenuItem jMenuDirScanResume;
+    private javax.swing.JMenuItem jMenuItem1;
+    private javax.swing.JMenuItem jMenuItem10;
+    private javax.swing.JMenuItem jMenuItem11;
+    private javax.swing.JMenuItem jMenuItem2;
+    private javax.swing.JMenuItem jMenuItem3;
+    private javax.swing.JMenuItem jMenuItem4;
+    private javax.swing.JMenuItem jMenuItem5;
+    private javax.swing.JMenuItem jMenuItem6;
+    private javax.swing.JMenuItem jMenuItem7;
+    private javax.swing.JMenuItem jMenuItem8;
+    private javax.swing.JMenuItem jMenuItem9;
+    private javax.swing.JMenuItem jMenuItemActiveUsers;
+    private javax.swing.JMenuItem jMenuItemChangePassword;
+    private javax.swing.JMenuItem jMenuItemDcm2jpeg2;
+    private javax.swing.JMenuItem jMenuItemPreferences;
+    private javax.swing.JMenuItem jMenuItemServices;
+    private javax.swing.JMenuItem jMenuItemShutdown;
+    private javax.swing.JMenuItem jMenuItemUsers;
+    private javax.swing.JMenu jMenuTools2;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JPanel jPanel3;
+    private javax.swing.JPanel jPanel4;
+    private javax.swing.JPanel jPanel5;
+    private javax.swing.JPanel jPanel6;
+    private javax.swing.JPanel jPanel8;
+    private javax.swing.JPanel jPanel9;
+    private javax.swing.JPanel jPanelThumbnail;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JScrollPane jScrollPane2;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JSeparator jSeparator2;
+    private javax.swing.JSeparator jSeparator3;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JTextField jTextFieldQuery;
+    private javax.swing.JTree jTreeResults;
+    private javax.swing.JMenu pluginMenu;
+    private javax.swing.JTabbedPane tabPanel;
+    // End of variables declaration//GEN-END:variables
+
+    /**
+     * ************************************************
+     * Public Methods
+     *************************************************
+     */
+    /**
+     * Checks if the options form is displayed
+     *
+     * @return true if not displaying, true otherwise
+     */
+    private void showMetaData() {
+        /**
+         * Just show metadata for now
+         *
+         */
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTreeResults.getLastSelectedPathComponent();
+
+        if (node != null && node.isLeaf() && node.getLevel() > 3) {
+
+            Object nodeInfo = node.getUserObject();
+            SearchResult fileInfo = (SearchResult) nodeInfo;
+
+            if (nodeInfo instanceof SearchResult) {
+                IndexedMetaData metadataWindow = new IndexedMetaData(fileInfo, this);
+                metadataWindow.setVisible(true);
+                metadataWindow.toFront();
+            }
+        }
+    }
+
+    public void showImage(String title, RenderedImage image) {
+        if (jPanelThumbnail == null) {
+
+            // It can be used to show image in external window
+            JFrame f = new JFrame(title);
+            if (image != null) {
+                f.getContentPane().add(new DisplayJAI(image));
+            }
+            f.pack();
+            //f.setVisible(true);
+            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        } else {
+            jPanelThumbnail.removeAll();
+            jPanelThumbnail.setLayout(new FlowLayout());
+
+            // Yet another bugfix
+            // If the indexed image does not have a thumbnail, it leads to a Null Pointer Exception
+            if (image != null) {
+                jPanelThumbnail.add(new DisplayJAI(image));
+            }
+
+            jPanelThumbnail.validate();
+            jPanelThumbnail.setVisible(true);
+        }
+    }
+
+    /**
+     * @return the jLabelResults
+     */
+    public javax.swing.JLabel getjLabelResults() {
+        return jLabelResults;
+    }
+
+    /**
+     * @param jLabelResults the jLabelResults to set
+     */
+    public void setjLabelResults(javax.swing.JLabel jLabelResults) {
+        this.jLabelResults = jLabelResults;
+    }
+
+    /**
+     * @return the jLabelTime
+     */
+    public javax.swing.JLabel getjLabelTime() {
+        return jLabelTime;
+    }
+
+    /**
+     * @param jLabelTime the jLabelTime to set
+     */
+    public void setjLabelTime(javax.swing.JLabel jLabelTime) {
+        this.jLabelTime = jLabelTime;
+    }
+
+    /**
+     * @return the jTreeResults
+     */
+    public javax.swing.JTree getjTreeResults() {
+        return jTreeResults;
+    }
+
+    /**
+     * @param jTreeResults the jTreeResults to set
+     */
+    public void setjTreeResults(javax.swing.JTree jTreeResults) {
+        this.jTreeResults = jTreeResults;
+    }
+
+    private void showThumbnail(String thumb) {
+        if (thumb == null) {
+            return;
+        }
+
+        byte[] tb = Base64.decodeBase64(thumb.getBytes());
+        ByteArrayInputStream in = new ByteArrayInputStream(tb);
+        RenderedImage out;
+        try {
+            out = ImageIO.read(in);
+            jPanelThumbnail.setSize(64, 64);
+            Result2Tree.showImage("Image Thumbnail", out, jPanelThumbnail);
+            repaint();
+        } catch (IOException ex) {
+            cleanThumbnails();
+        }
+    }
+
+    private String getAdvancedQuery() {
+        boolean modified = false;
+        String advancedquery = "";
+
+        if (!((PatientName.getText()).equals("(All patients)")) && !((PatientName.getText()).isEmpty())) {
+            if (!modified) {
+                advancedquery = (advancedquery + "PatientName:(" + PatientName.getText() + ")");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND PatientName:(" + PatientName.getText() + ")");
+            }
+        }
+
+        if (!((PatientID.getText()).equals("(All IDs)")) && !((PatientID.getText()).isEmpty())) {
+            if (!modified) {
+                advancedquery = (advancedquery + "PatientID:(" + PatientID.getText() + ")");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND PatientID:(" + PatientID.getText() + ")");
+            }
+        }
+
+        // 0 - All 1 - Male  1 - Female
+        if (PatientGender.getSelectedItem().equals("All")) {
+        } else if (PatientGender.getSelectedItem().equals("Male")) {
+            if (!modified) {
+                advancedquery = (advancedquery + "PatientSex:M");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND PatientSex:M");
+            }
+        } else if (PatientGender.getSelectedItem().equals("Female")) {
+            if (!modified) {
+                advancedquery = (advancedquery + "PatientSex:F");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND PatientSex:F");
+            }
+        }
+
+        if (!((InstitutionName.getText()).equals("(All institutions)")) && !((InstitutionName.getText()).isEmpty())) {
+            if (!modified) {
+                advancedquery = (advancedquery + "InstitutionName:(" + InstitutionName.getText() + ")");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND InstitutionName:(" + InstitutionName.getText() + ")");
+            }
+        }
+
+        if (!((Physician.getText()).equals("(All physicians)")) && !((Physician.getText()).isEmpty())) {
+            if (!modified) {
+                advancedquery = (advancedquery + "(PerformingPhysicianName:(" + Physician.getText() + ") OR ReferringPhysicianName:(" + Physician.getText() + "))");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND (PerformingPhysicianName:(" + Physician.getText() + ") OR ReferringPhysicianName:(" + Physician.getText() + "))");
+            }
+        }
+
+        if (!((OperatorName.getText()).equals("(All operators)")) && !((OperatorName.getText()).isEmpty())) {
+            if (!modified) {
+                advancedquery = (advancedquery + "OperatorName:(" + OperatorName.getText() + ")");
+                modified = true;
+            } else {
+                advancedquery = (advancedquery + " AND OperatorName:(" + OperatorName.getText() + ")");
+            }
+        }
+
+        if (ExactDate.isSelected()) {
+            if (!((StudyDate.getText()).equals("(All dates)")) && !((StudyDate.getText()).isEmpty())) {
+                if (!modified) {
+                    advancedquery = (advancedquery + "StudyDate:(" + StudyDate.getText() + ")");
+                    modified = true;
+                } else {
+                    advancedquery = (advancedquery + " AND StudyDate:(" + StudyDate.getText() + ")");
+                }
+            }
+        } else {
+            //http://www.rgagnon.com/javadetails/java-0106.html
+            Calendar cal = Calendar.getInstance();
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+            //sdf.format(cal.getTime());
+
+            if (modified) {
+                advancedquery = (advancedquery + " AND StudyDate:[");
+            } else {
+                advancedquery = advancedquery + "StudyDate:[";
+            }
+            modified = true;
+
+            if (StudyDateRangeInitialBoundaryActivation.isSelected() && StudyDateRangeTerminalBoundaryActivation.isSelected()) {
+                if (((StudyDateRangeInitialBoundary.getText()).equals("(Beginning)")) || ((StudyDateRangeInitialBoundary.getText()).isEmpty())) {
+                    advancedquery = (advancedquery + "0000101 TO ");
+                } else {
+                    advancedquery = advancedquery + StudyDateRangeInitialBoundary.getText() + " TO ";
+                }
+
+                if (((StudyDateRangeTerminalBoundary.getText()).equals("(Today)")) || ((StudyDateRangeTerminalBoundary.getText()).isEmpty())) {
+                    advancedquery = advancedquery + sdf.format(cal.getTime()) + "]";
+                } else {
+                    advancedquery = advancedquery + StudyDateRangeTerminalBoundary.getText() + "]";
+                }
+            } else if (StudyDateRangeInitialBoundaryActivation.isSelected() && !StudyDateRangeTerminalBoundaryActivation.isSelected()) {
+                if (((StudyDateRangeInitialBoundary.getText()).equals("(Beginning)")) || ((StudyDateRangeInitialBoundary.getText()).isEmpty())) {
+                    advancedquery = (advancedquery + "0000101 TO ");
+                } else {
+                    advancedquery = advancedquery + StudyDateRangeInitialBoundary.getText() + " TO ";
+                }
+
+                advancedquery = advancedquery + sdf.format(cal.getTime()) + "]";
+            } else if (!StudyDateRangeInitialBoundaryActivation.isSelected() && StudyDateRangeTerminalBoundaryActivation.isSelected()) {
+                advancedquery = advancedquery + "0000101 TO ";
+                if (((StudyDateRangeTerminalBoundary.getText()).equals("(Today)")) || ((StudyDateRangeTerminalBoundary.getText()).isEmpty())) {
+                    advancedquery = advancedquery + sdf.format(cal.getTime()) + "]";
+                } else {
+                    advancedquery = advancedquery + StudyDateRangeTerminalBoundary.getText() + "]";
+                }
+
+            } else {
+                advancedquery = (advancedquery + "0000101 TO ");
+                advancedquery = advancedquery + sdf.format(cal.getTime()) + "]";
+            }
+        }
+
+        if (ModalSelectAll.isSelected()) {
+            if (modified) {
+                advancedquery = advancedquery + " AND ";
+            }
+
+            advancedquery = advancedquery + "*:*";
+        } else {
+            String modalities = "";
+            if (modified) {
+                modalities = modalities + " AND (";
+            } else {
+                modalities = modalities + "(";
+            }
+            boolean ModSelected = false;
+
+            if (ModalCR.isSelected()) {
+                modified = true;
+                ModSelected = true;
+                modalities = modalities + "Modality:CR";
+            }
+
+            if (ModalCT.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:CT";
+            }
+
+            if (ModalDX.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:DX";
+            }
+
+            if (ModalES.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:ES";
+            }
+
+            if (ModalMG.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:MG";
+            }
+
+            if (ModalMR.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:MR";
+            }
+
+            if (ModalNM.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:NM";
+            }
+
+            if (ModalOT.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:OT";
+            }
+
+            if (ModalPT.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:PT";
+            }
+
+            if (ModalRF.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:RF";
+            }
+
+            if (ModalSC.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:SC";
+            }
+
+            if (ModalUS.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:US";
+            }
+
+            if (ModalXA.isSelected()) {
+                modified = true;
+                if (ModSelected) {
+                    modalities = modalities + " OR ";
+                }
+                ModSelected = true;
+                modalities = modalities + "Modality:XA";
+            }
+
+            modalities = modalities + ")";
+
+            if (!modalities.equals(" AND ()")) {
+                advancedquery = advancedquery + modalities;
+            }
+        }
+
+        // System.out.println(modalities);
+        if (!modified) {
+            advancedquery = "*:*";
+        }
+
+        return advancedquery;
+    }
+
+    public javax.swing.JMenu getMenu() {
+        return jMenuTools2;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.form
new file mode 100755
index 0000000..6146850
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.form
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Query/Retrieve Storage Servers"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel5" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel5" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel5">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Storage Servers Destinations"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="0" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jTextFieldQRAETitle" alignment="0" pref="218" max="32767" attributes="1"/>
+                                      <Component id="jTextFieldQRIP" alignment="1" pref="218" max="32767" attributes="1"/>
+                                  </Group>
+                                  <EmptySpace type="separate" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                                      <Component id="jButtonQRRemoveEntry" alignment="1" min="0" pref="0" max="32767" attributes="1"/>
+                                      <Component id="jButtonQRAddEntry" alignment="1" min="-2" pref="114" max="-2" attributes="1"/>
+                                  </Group>
+                              </Group>
+                              <Component id="jTextFieldQRPort" alignment="0" min="-2" pref="91" max="-2" attributes="0"/>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jScrollPane5" min="-2" pref="152" max="-2" attributes="0"/>
+                      </Group>
+                      <Component id="jButtonWrite" alignment="1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jTextFieldQRAETitle" alignment="3" min="-2" max="-2" attributes="0"/>
+                              </Group>
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Component id="jButtonQRAddEntry" min="-2" max="-2" attributes="0"/>
+                                  <EmptySpace max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="3" attributes="0">
+                                      <Component id="jButtonQRRemoveEntry" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jTextFieldQRIP" alignment="3" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                              </Group>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="jTextFieldQRPort" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <Component id="jScrollPane5" min="-2" pref="118" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace pref="19" max="32767" attributes="0"/>
+                  <Component id="jButtonWrite" min="-2" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JButton" name="jButtonQRAddEntry">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="new ImageIcon(getImage("add.png"))" type="code"/>
+            </Property>
+            <Property name="text" type="java.lang.String" value="Add Entry"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonQRAddEntryActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JButton" name="jButtonQRRemoveEntry">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="new ImageIcon(getImage("remove.png"))" type="code"/>
+            </Property>
+            <Property name="text" type="java.lang.String" value="Remove"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonQRRemoveEntryActionPerformed"/>
+          </Events>
+        </Component>
+        <Container class="javax.swing.JScrollPane" name="jScrollPane5">
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JList" name="jListQRMoveDest">
+              <Properties>
+                <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+                  <StringArray count="0"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jListQRMoveDestMouseClicked"/>
+                <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="jListQRMoveDestValueChanged"/>
+              </Events>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JList(modelQRMoveDest)"/>
+                <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="DefaultListModel modelQRMoveDest = new DefaultListModel();"/>
+              </AuxValues>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="AETitle:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="jTextFieldQRAETitle">
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="IP:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel3">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Port:"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JTextField" name="jTextFieldQRIP">
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTextField()"/>
+            <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="AllowBlankMaskFormatter maskSub = null;&#xa;try &#xa;{&#xa;    maskSub = new AllowBlankMaskFormatter("###.###.###.###");&#xa;    maskSub.setPlaceholderCharacter(' ');&#xa;    maskSub.setAllowBlankField(true);&#xa;    //maskSub.setValidCharacters("0123456789");&#xa;    //maskSub.setInvalidCharacters("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz");&#xa [...]
+          </AuxValues>
+        </Component>
+        <Component class="javax.swing.JTextField" name="jTextFieldQRPort">
+        </Component>
+        <Component class="javax.swing.JButton" name="jButtonWrite">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+              <Connection code="new ImageIcon(getImage("floopy-icon.png"))" type="code"/>
+            </Property>
+            <Property name="text" type="java.lang.String" value="Save Configurations"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonWriteActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.java
new file mode 100755
index 0000000..0d3ac0d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QRServers.java
@@ -0,0 +1,398 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * QRSettings.java
+ *
+ * Created on 15/Dez/2009, 11:34:31
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.rmi.RemoteException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+
+import java.util.Hashtable;
+import java.util.concurrent.Semaphore;
+
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQRServers;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.client.UIHelper.AllowBlankMaskFormatter;
+
+/**
+ * Query/Retrieve Storage Servers configuration
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class QRServers extends javax.swing.JFrame {
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static QRServers instance = null;
+    private static IQRServers qrserv;
+
+    private Hashtable<String, MoveDestination> listMove = new Hashtable<String, MoveDestination>();
+
+
+    public static synchronized QRServers getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new QRServers();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+//            LoggerFactory.getLogger(MainWindow.class.getName()).log(Level.FATAL, null, ex);
+        }
+        return instance;
+    }
+
+
+    /** Creates new form QRSettings */
+    private QRServers() {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        QRServers.qrserv = AdminRefs.getInstance().getQRservers();
+
+        loadMove();
+    }
+
+ public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel5 = new javax.swing.JPanel();
+        jButtonQRAddEntry = new javax.swing.JButton();
+        jButtonQRRemoveEntry = new javax.swing.JButton();
+        jScrollPane5 = new javax.swing.JScrollPane();
+        DefaultListModel modelQRMoveDest = new DefaultListModel();
+        jListQRMoveDest = new JList(modelQRMoveDest);
+        jLabel1 = new javax.swing.JLabel();
+        jTextFieldQRAETitle = new javax.swing.JTextField();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        AllowBlankMaskFormatter maskSub = null;
+        try
+        {
+            maskSub = new AllowBlankMaskFormatter("###.###.###.###");
+            maskSub.setPlaceholderCharacter(' ');
+            maskSub.setAllowBlankField(true);
+            //maskSub.setValidCharacters("0123456789");
+            //maskSub.setInvalidCharacters("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz");
+        }
+        catch (java.text.ParseException e)
+        {
+            String pass = null ;
+        }
+        //jTextFieldQRIP = new JFormattedTextField(maskSub);
+        jTextFieldQRIP = new JTextField();
+        jTextFieldQRPort = new javax.swing.JTextField();
+        jButtonWrite = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Query/Retrieve Storage Servers");
+        setResizable(false);
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        jPanel5.setBorder(javax.swing.BorderFactory.createTitledBorder("Storage Servers Destinations"));
+
+        jButtonQRAddEntry.setIcon(new ImageIcon(getImage("add.png")));
+        jButtonQRAddEntry.setText("Add Entry");
+        jButtonQRAddEntry.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonQRAddEntryActionPerformed(evt);
+            }
+        });
+
+        jButtonQRRemoveEntry.setIcon(new ImageIcon(getImage("remove.png")));
+        jButtonQRRemoveEntry.setText("Remove");
+        jButtonQRRemoveEntry.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonQRRemoveEntryActionPerformed(evt);
+            }
+        });
+
+        jListQRMoveDest.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jListQRMoveDestMouseClicked(evt);
+            }
+        });
+        jListQRMoveDest.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
+                jListQRMoveDestValueChanged(evt);
+            }
+        });
+        jScrollPane5.setViewportView(jListQRMoveDest);
+
+        jLabel1.setText("AETitle:");
+
+        jLabel2.setText("IP:");
+
+        jLabel3.setText("Port:");
+
+        jButtonWrite.setIcon(new ImageIcon(getImage("floopy-icon.png")));
+        jButtonWrite.setText("Save Configurations");
+        jButtonWrite.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonWriteActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
+        jPanel5.setLayout(jPanel5Layout);
+        jPanel5Layout.setHorizontalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel5Layout.createSequentialGroup()
+                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jLabel1)
+                            .addComponent(jLabel3)
+                            .addComponent(jLabel2))
+                        .addGap(24, 24, 24)
+                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addGroup(jPanel5Layout.createSequentialGroup()
+                                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                    .addComponent(jTextFieldQRAETitle, javax.swing.GroupLayout.DEFAULT_SIZE, 218, Short.MAX_VALUE)
+                                    .addComponent(jTextFieldQRIP, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 218, Short.MAX_VALUE))
+                                .addGap(18, 18, 18)
+                                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                                    .addComponent(jButtonQRRemoveEntry, 0, 1, Short.MAX_VALUE)
+                                    .addComponent(jButtonQRAddEntry, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                            .addComponent(jTextFieldQRPort, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jScrollPane5, javax.swing.GroupLayout.PREFERRED_SIZE, 152, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(jButtonWrite, javax.swing.GroupLayout.Alignment.TRAILING))
+                .addGap(20, 20, 20))
+        );
+        jPanel5Layout.setVerticalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel5Layout.createSequentialGroup()
+                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                                .addComponent(jLabel1)
+                                .addComponent(jTextFieldQRAETitle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                            .addGroup(jPanel5Layout.createSequentialGroup()
+                                .addComponent(jButtonQRAddEntry)
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                                    .addComponent(jButtonQRRemoveEntry)
+                                    .addComponent(jTextFieldQRIP, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                    .addComponent(jLabel2))))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jLabel3)
+                            .addComponent(jTextFieldQRPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                    .addComponent(jScrollPane5, javax.swing.GroupLayout.PREFERRED_SIZE, 118, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 19, Short.MAX_VALUE)
+                .addComponent(jButtonWrite))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    
+    public void loadMove()
+    {
+        try {
+
+            DefaultListModel m = (DefaultListModel) jListQRMoveDest.getModel();
+            m.clear();
+
+            for (MoveDestination s : qrserv.getMoves()) {
+                //DebugManager.getInstance().debug(s.getAETitle());
+
+                int pos = jListQRMoveDest.getModel().getSize();
+                m.add(pos, s.getAETitle());
+                listMove.put(s.getAETitle(), s);
+            }
+            
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+
+    }
+
+    private void jButtonQRAddEntryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonQRAddEntryActionPerformed
+        if (jTextFieldQRAETitle.getText().equals("") || jTextFieldQRIP.getText().equals("") || jTextFieldQRPort.getText().equals("")) {
+            JOptionPane.showMessageDialog(this, "Please, fill all fields!",
+                    "Missing fields", JOptionPane.WARNING_MESSAGE);
+
+        } else {
+            String aeTitleDest = jTextFieldQRAETitle.getText();
+            if (!listMove.containsKey(aeTitleDest)) {
+                DefaultListModel m = (DefaultListModel) jListQRMoveDest.getModel();
+                m.addElement(aeTitleDest);
+
+                MoveDestination tmpMove = new MoveDestination(aeTitleDest,
+                        jTextFieldQRIP.getText(), Integer.parseInt(jTextFieldQRPort.getText()));
+                
+                listMove.put(aeTitleDest, tmpMove);
+                
+                try {
+                    qrserv.AddEntry(tmpMove);
+                    
+                } catch (RemoteException ex) {
+                    LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+                }
+
+            
+            } else {
+                JOptionPane.showMessageDialog(this, "The AETtitle already exists in the list",
+                        "AETitle", JOptionPane.WARNING_MESSAGE);
+            }
+
+        }
+}//GEN-LAST:event_jButtonQRAddEntryActionPerformed
+
+    private void jButtonQRRemoveEntryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonQRRemoveEntryActionPerformed
+
+
+        // Remove Destination
+
+        if (jListQRMoveDest.getSelectedIndex() == -1 ) {
+            JOptionPane.showMessageDialog(this, "Please select an AETitle in the list",
+                    "No selected item", JOptionPane.WARNING_MESSAGE);
+        } else {
+            String aeTitleSelected = null;
+            aeTitleSelected = (String) jListQRMoveDest.getSelectedValue();
+            DefaultListModel m = (DefaultListModel) jListQRMoveDest.getModel();
+
+            m.removeElement(jListQRMoveDest.getSelectedValue());
+            MoveDestination tmp = listMove.get(aeTitleSelected);
+            listMove.remove(aeTitleSelected);
+            
+            try {
+                qrserv.RemoveEntry(tmp);
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+            }
+
+        }
+}//GEN-LAST:event_jButtonQRRemoveEntryActionPerformed
+
+    private void jListQRMoveDestValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListQRMoveDestValueChanged
+        // Show ip address and port number ;
+
+        if (jListQRMoveDest.getSelectedIndex() == -1 )
+            return ;
+        String sel = (String) jListQRMoveDest.getSelectedValue();
+        MoveDestination tmp = listMove.get(sel);
+
+        jTextFieldQRAETitle.setText(tmp.getAETitle());
+        jTextFieldQRIP.setText(tmp.getIpAddrs());
+        jTextFieldQRPort.setText(String.valueOf(tmp.getPort()));
+    }//GEN-LAST:event_jListQRMoveDestValueChanged
+
+    private void jListQRMoveDestMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListQRMoveDestMouseClicked
+
+}//GEN-LAST:event_jListQRMoveDestMouseClicked
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        Services services = Services.getInstance();
+
+        //if(services != null && services.isVisible()){
+            services.toFront();
+            services.setEnabled(true);
+        /*
+        }
+        else{
+            ServerOptions serverOptions = ServerOptions.getInstance();
+
+            serverOptions.toFront();
+            serverOptions.setEnabled(true);
+        }
+         *
+         */
+
+        this.dispose();
+    }//GEN-LAST:event_formWindowClosing
+
+    private void jButtonWriteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonWriteActionPerformed
+        AdminRefs.getInstance().saveSettings();
+}//GEN-LAST:event_jButtonWriteActionPerformed
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonQRAddEntry;
+    private javax.swing.JButton jButtonQRRemoveEntry;
+    private javax.swing.JButton jButtonWrite;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JList jListQRMoveDest;
+    private javax.swing.JPanel jPanel5;
+    private javax.swing.JScrollPane jScrollPane5;
+    private javax.swing.JTextField jTextFieldQRAETitle;
+    private javax.swing.JTextField jTextFieldQRIP;
+    private javax.swing.JTextField jTextFieldQRPort;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.form
new file mode 100755
index 0000000..416bca4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.form
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Query History"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[490, 270]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jScrollPane1" pref="309" max="32767" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                              <Component id="jButtonDeleteAll" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jButtonDeleteThis" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jButtonInsert" alignment="0" max="32767" attributes="1"/>
+                          </Group>
+                          <Component id="jButtonClose" alignment="0" min="-2" pref="150" max="-2" attributes="1"/>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="1" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Component id="jButtonInsert" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonDeleteThis" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonDeleteAll" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="84" max="32767" attributes="0"/>
+                      <Component id="jButtonClose" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="1" attributes="0">
+                      <EmptySpace min="1" pref="1" max="1" attributes="0"/>
+                      <Component id="jScrollPane1" pref="207" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListQueryHistory">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+            <Property name="selectionMode" type="int" value="0"/>
+          </Properties>
+          <Events>
+            <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jListQueryHistoryMouseClicked"/>
+          </Events>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="QueryHistory_jListQueryHistory"/>
+          </AuxValues>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="jButtonClose">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Close"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonCloseActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonInsert">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Insert into Query"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonInsertActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonDeleteThis">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Delete Query"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonDeleteThisActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonDeleteAll">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Delete All"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonDeleteAllActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Query History:"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.java
new file mode 100755
index 0000000..bff1845
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/QueryHistory.java
@@ -0,0 +1,263 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * QueryHistory.java
+ *
+ * Created on 21/Jul/2010, 0:04:27
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.util.Iterator;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JCheckBox;
+import javax.swing.JOptionPane;
+import javax.swing.JTextField;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.QueryHistoryEntry;
+import pt.ua.dicoogle.core.QueryHistorySupport;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at Deprecated
+public class QueryHistory extends javax.swing.JFrame implements Observer {
+    private QueryHistorySupport QHS = QueryHistorySupport.getInstance();
+    private JTextField queryField = null;
+    private JCheckBox jCheckBoxKeywords = null;
+
+    private static QueryHistory instance = null;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized QueryHistory getInstance()
+    {
+        try
+        {
+            sem.acquire();
+            if (instance == null)
+            {
+                instance = new QueryHistory();
+            }
+            sem.release();
+        }
+        catch (InterruptedException ex)
+        {
+            LoggerFactory.getLogger(QueryHistory.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    /** Creates new form QueryHistory */
+    private QueryHistory() {
+        initComponents();
+
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        QHS.addObserver(this);
+        
+        updateList();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jListQueryHistory = new javax.swing.JList();
+        jButtonClose = new javax.swing.JButton();
+        jButtonInsert = new javax.swing.JButton();
+        jButtonDeleteThis = new javax.swing.JButton();
+        jButtonDeleteAll = new javax.swing.JButton();
+        jLabel2 = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Query History");
+        setMinimumSize(new java.awt.Dimension(490, 270));
+
+        jListQueryHistory.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+        jListQueryHistory.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jListQueryHistoryMouseClicked(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jListQueryHistory);
+
+        jButtonClose.setText("Close");
+        jButtonClose.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonCloseActionPerformed(evt);
+            }
+        });
+
+        jButtonInsert.setText("Insert into Query");
+        jButtonInsert.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonInsertActionPerformed(evt);
+            }
+        });
+
+        jButtonDeleteThis.setText("Delete Query");
+        jButtonDeleteThis.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonDeleteThisActionPerformed(evt);
+            }
+        });
+
+        jButtonDeleteAll.setText("Delete All");
+        jButtonDeleteAll.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonDeleteAllActionPerformed(evt);
+            }
+        });
+
+        jLabel2.setFont(new java.awt.Font("Lucida Grande", 1, 13));
+        jLabel2.setText("Query History:");
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .addContainerGap()
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(jLabel2)
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 309, Short.MAX_VALUE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
+                                .add(jButtonDeleteAll, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .add(jButtonDeleteThis, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                .add(jButtonInsert, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                            .add(jButtonClose, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 150, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(20, 20, 20)
+                .add(jLabel2)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                    .add(layout.createSequentialGroup()
+                        .add(jButtonInsert)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonDeleteThis)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonDeleteAll)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 84, Short.MAX_VALUE)
+                        .add(jButtonClose))
+                    .add(layout.createSequentialGroup()
+                        .add(1, 1, 1)
+                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 207, Short.MAX_VALUE)))
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonCloseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonCloseActionPerformed
+        this.setVisible(false);
+        MainWindow.getInstance().toFront();
+        this.dispose();
+    }//GEN-LAST:event_jButtonCloseActionPerformed
+
+    private void jButtonInsertActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonInsertActionPerformed
+        QueryHistoryEntry<String, Boolean> query = (QueryHistoryEntry<String, Boolean>) jListQueryHistory.getSelectedValue() ;
+        if (query==null || query.getKey()==null)
+        {
+
+            JOptionPane.showMessageDialog(this, "Select a valid query.", "Missing query", JOptionPane.INFORMATION_MESSAGE);
+            return ;
+        }
+        queryField.setText(query.getKey());
+        jCheckBoxKeywords.setSelected(query.getValue());
+    }//GEN-LAST:event_jButtonInsertActionPerformed
+
+    private void jButtonDeleteAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDeleteAllActionPerformed
+        QHS.deleteAll();
+    }//GEN-LAST:event_jButtonDeleteAllActionPerformed
+
+    private void jButtonDeleteThisActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDeleteThisActionPerformed
+        QueryHistoryEntry<String, Boolean> query = (QueryHistoryEntry<String, Boolean>) jListQueryHistory.getSelectedValue() ;
+        if(query == null)
+            JOptionPane.showMessageDialog(this, "Please select one query to delete.", "Delete Query", JOptionPane.INFORMATION_MESSAGE);
+        else
+            QHS.deleteQuery(query);
+    }//GEN-LAST:event_jButtonDeleteThisActionPerformed
+
+    private void jListQueryHistoryMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListQueryHistoryMouseClicked
+        if (evt.getClickCount() == 2)
+              jButtonInsert.doClick();
+    }//GEN-LAST:event_jListQueryHistoryMouseClicked
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonClose;
+    private javax.swing.JButton jButtonDeleteAll;
+    private javax.swing.JButton jButtonDeleteThis;
+    private javax.swing.JButton jButtonInsert;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JList jListQueryHistory;
+    private javax.swing.JScrollPane jScrollPane1;
+    // End of variables declaration//GEN-END:variables
+
+
+     @Override
+    public void update(Observable o, Object arg) {
+        updateList();
+    }
+
+    private void updateList(){
+        Iterator<QueryHistoryEntry<String, Boolean>> it = QHS.getQueryHistory();
+
+        DefaultListModel listModel = new DefaultListModel();
+
+        while(it.hasNext())
+        {
+            listModel.addElement(it.next());
+        }
+        jListQueryHistory.setModel(listModel);
+    }
+
+    public void setJTextFieldQuery(JTextField queryField, JCheckBox jCheckBoxKeywords){
+        this.queryField = queryField;
+        this.jCheckBoxKeywords = jCheckBoxKeywords;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.form
new file mode 100755
index 0000000..02f12d3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.form
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.5" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Search Tips"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Group type="102" alignment="0" attributes="0">
+                              <EmptySpace min="12" pref="12" max="12" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Group type="103" groupAlignment="1" max="-2" attributes="0">
+                                          <Group type="102" alignment="0" attributes="1">
+                                              <Group type="103" groupAlignment="1" attributes="0">
+                                                  <Component id="jLabel6" alignment="0" min="-2" max="-2" attributes="0"/>
+                                                  <Component id="jLabel5" alignment="1" min="-2" max="-2" attributes="0"/>
+                                              </Group>
+                                              <EmptySpace max="-2" attributes="0"/>
+                                              <Component id="jTextFieldFiltering" max="32767" attributes="0"/>
+                                          </Group>
+                                          <Component id="jScrollPane1" alignment="0" min="-2" pref="354" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                                          <Component id="jButton3" max="32767" attributes="1"/>
+                                          <Component id="jButtonInsertQuery" alignment="0" max="32767" attributes="1"/>
+                                      </Group>
+                                  </Group>
+                              </Group>
+                          </Group>
+                      </Group>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="130" max="-2" attributes="0"/>
+                      <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="182" max="-2" attributes="0"/>
+                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jTextFieldFiltering" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="32767" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Component id="jScrollPane1" min="-2" pref="117" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jButton1" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" attributes="0">
+                      <Component id="jButtonInsertQuery" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButton3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Search tips:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="With default search, you can use boolean expressions, with operators like AND, OR."/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="You can provide specific fields value. For example:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel4">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="PatientName:"John Doe""/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel5">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="The fields supported are:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Close"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButton1ActionPerformed"/>
+      </Events>
+    </Component>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListElements">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="jListElementsMouseClicked"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JTextField" name="jTextFieldFiltering">
+      <Events>
+        <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTextFieldFilteringKeyReleased"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel6">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Insert the tag name:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonInsertQuery">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Insert into Query"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonInsertQueryActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButton3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="See Details"/>
+        <Property name="enabled" type="boolean" value="false"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.java
new file mode 100755
index 0000000..eb32349
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/SearchTips.java
@@ -0,0 +1,309 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * SearchTips.java
+ *
+ * Created on December 8, 2007, 12:53 AM
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.rmi.RemoteException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.*;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.swing.DefaultListModel;
+import javax.swing.JTextField;
+import pt.ua.dicoogle.rGUI.client.UserRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+
+/**
+ *
+ * @author  filipe
+ */
+ at Deprecated
+public class SearchTips extends javax.swing.JFrame {
+    private MainWindow aThis = MainWindow.getInstance();
+    private JTextField query = null;
+    private ISearch search;
+    private HashMap tags;
+    
+    public SearchTips(JTextField query)
+    {
+        try {
+            this.query = query;
+            initComponents();
+
+            //this.aThis.setEnabled(false);
+            this.search = UserRefs.getInstance().getSearch();
+
+            tags = search.getTagList();
+
+            Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+            this.setIconImage(image);
+            
+            updateList(null);
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(SearchTips.class).error(ex.getMessage(), ex);
+        }
+
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jLabel4 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        jButton1 = new javax.swing.JButton();
+        jScrollPane1 = new javax.swing.JScrollPane();
+        jListElements = new javax.swing.JList();
+        jTextFieldFiltering = new javax.swing.JTextField();
+        jLabel6 = new javax.swing.JLabel();
+        jButtonInsertQuery = new javax.swing.JButton();
+        jButton3 = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Search Tips");
+        setResizable(false);
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        jLabel1.setText("Search tips:");
+
+        jLabel2.setText("With default search, you can use boolean expressions, with operators like AND, OR.");
+
+        jLabel3.setText("You can provide specific fields value. For example:");
+
+        jLabel4.setText("PatientName:\"John Doe\"");
+
+        jLabel5.setText("The fields supported are:");
+
+        jButton1.setText("Close");
+        jButton1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButton1ActionPerformed(evt);
+            }
+        });
+
+        jListElements.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                jListElementsMouseClicked(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jListElements);
+
+        jTextFieldFiltering.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyReleased(java.awt.event.KeyEvent evt) {
+                jTextFieldFilteringKeyReleased(evt);
+            }
+        });
+
+        jLabel6.setText("Insert the tag name:");
+
+        jButtonInsertQuery.setText("Insert into Query");
+        jButtonInsertQuery.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonInsertQueryActionPerformed(evt);
+            }
+        });
+
+        jButton3.setText("See Details");
+        jButton3.setEnabled(false);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jLabel1)
+                            .addGroup(layout.createSequentialGroup()
+                                .addGap(12, 12, 12)
+                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                    .addComponent(jLabel2)
+                                    .addComponent(jLabel3)
+                                    .addGroup(layout.createSequentialGroup()
+                                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
+                                            .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+                                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                                                    .addComponent(jLabel6, javax.swing.GroupLayout.Alignment.LEADING)
+                                                    .addComponent(jLabel5))
+                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                                .addComponent(jTextFieldFiltering))
+                                            .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 354, javax.swing.GroupLayout.PREFERRED_SIZE))
+                                        .addGap(30, 30, 30)
+                                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                                            .addComponent(jButton3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                            .addComponent(jButtonInsertQuery, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(130, 130, 130)
+                        .addComponent(jLabel4))
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(182, 182, 182)
+                        .addComponent(jButton1)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel3)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel4)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel5)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel6)
+                    .addComponent(jTextFieldFiltering, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(jButton1))
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(jButtonInsertQuery)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jButton3)))
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
+            this.setVisible(false);
+            aThis.setEnabled(true);
+            aThis.toFront();
+            this.dispose();
+    }//GEN-LAST:event_jButton1ActionPerformed
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+            this.setVisible(false);
+            aThis.setEnabled(true);
+            aThis.toFront();
+    }//GEN-LAST:event_formWindowClosing
+
+    private void jButtonInsertQueryActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonInsertQueryActionPerformed
+        String tagName = (String) jListElements.getSelectedValue() ;
+        
+        if (tagName == null)
+            return;
+
+        if(query.getText().equals(""))
+            query.setText(tagName +":");
+        else
+            query.setText(query.getText()+ " " + tagName +":");
+    }//GEN-LAST:event_jButtonInsertQueryActionPerformed
+
+    private void jListElementsMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jListElementsMouseClicked
+          if (evt.getClickCount() == 2)
+              jButtonInsertQuery.doClick();
+    }//GEN-LAST:event_jListElementsMouseClicked
+
+    private void jTextFieldFilteringKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextFieldFilteringKeyReleased
+        updateList(jTextFieldFiltering.getText());
+    }//GEN-LAST:event_jTextFieldFilteringKeyReleased
+
+
+
+    private void updateList(String prefix)
+    {
+
+        DefaultListModel listModel;
+        listModel = new DefaultListModel();
+
+        Set<String> set = getTagList(prefix);
+
+        Iterator<String> it = (Iterator<String>) set.iterator();
+        while(it.hasNext())
+        {
+            String tagName = it.next();
+            listModel.addElement(tagName);
+        }
+        jListElements.setModel(listModel);
+
+    }
+
+
+    private Set<String> getTagList(String prefix) {
+        Set<String> set = new TreeSet<String>();
+
+        Set<String> sset = tags.keySet();
+
+        for (String item : sset) {
+            if (prefix != null && !prefix.equals("")) {
+                if (item.toLowerCase().startsWith(prefix.toLowerCase())) {
+                    set.add(item);
+                }
+            } else {
+                set.add(item);
+            }
+        }
+
+        return set;
+    }
+
+
+        
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButton1;
+    private javax.swing.JButton jButton3;
+    private javax.swing.JButton jButtonInsertQuery;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel6;
+    private javax.swing.JList jListElements;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JTextField jTextFieldFiltering;
+    // End of variables declaration//GEN-END:variables
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.form
new file mode 100755
index 0000000..dde1993
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.form
@@ -0,0 +1,397 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Dicoogle Services"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="32767" attributes="0"/>
+              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="jSeparator1" alignment="0" max="32767" attributes="1"/>
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
+                  <Component id="jPanel3" max="32767" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+              </Group>
+              <Group type="102" attributes="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
+                          <Component id="jPanel5" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="jPanel2" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jPanel4" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
+                          <Component id="jPanel6" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="0" attributes="0">
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="jLabel12" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace min="97" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jPanel3" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jSeparator1" min="-2" pref="12" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                              <Component id="jPanel4" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jPanel2" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jPanel5" alignment="0" max="32767" attributes="1"/>
+                          </Group>
+                          <EmptySpace pref="26" max="32767" attributes="0"/>
+                          <Component id="jLabel12" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" attributes="0">
+                          <Component id="jPanel6" min="-2" max="-2" attributes="1"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JSeparator" name="jSeparator1">
+        </Component>
+        <Container class="javax.swing.JPanel" name="jPanel2">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel8" alignment="0" pref="90" max="32767" attributes="0"/>
+                          <Component id="jLabel9" alignment="1" pref="90" max="32767" attributes="1"/>
+                          <Component id="jLabel10" alignment="0" pref="90" max="32767" attributes="0"/>
+                          <Component id="jLabel11" alignment="0" pref="90" max="32767" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jLabel9" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                      <Component id="jLabel10" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                      <Component id="jLabel11" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="76" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel8">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="status"/>
+              </Properties>
+              <AccessibilityProperties>
+                <Property name="AccessibleContext.accessibleName" type="java.lang.String" value="storageStatusLabel"/>
+              </AccessibilityProperties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel9">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="status"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel10">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="status"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel11">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="status"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel3">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
+                      <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="90" max="-2" attributes="0"/>
+                      <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="72" max="-2" attributes="0"/>
+                      <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel3" alignment="3" min="-2" pref="16" max="-2" attributes="0"/>
+                          <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Service"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Status"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Control"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel5">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel5" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel6" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel7" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                      <Component id="jLabel6" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="separate" max="-2" attributes="0"/>
+                      <Component id="jLabel7" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="76" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="DICOM Storage:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel5">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="DICOM Query/Retrieve:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel6">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Dicoogle Web:"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel7">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Dicoogle WebServices:"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel4">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jButtonQR" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jButtonStorage" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jButtonWeb" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jButtonWebServices" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace pref="16" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <Component id="jButtonStorage" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonQR" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonWeb" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonWebServices" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="60" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="jButtonStorage">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("playSmall.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Start"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonStorageActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonQR">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("playSmall.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Start"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonQRActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonWeb">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("playSmall.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Start"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonWebActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JButton" name="jButtonWebServices">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("playSmall.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Start"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonWebServicesActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Container class="javax.swing.JPanel" name="jPanel6">
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonQRStorageServers" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="111" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
+                      <Component id="jButtonQRStorageServers" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace pref="113" max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JButton" name="jButtonQRStorageServers">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new ImageIcon(getImage("data-server.png"))" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Storage Servers"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonQRStorageServersActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Component class="javax.swing.JLabel" name="jLabel12">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="To define Dicoogle Inicial Services go to: Preferences -> Inicial Services"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.java
new file mode 100755
index 0000000..98fdf05
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/Services.java
@@ -0,0 +1,854 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.rmi.RemoteException;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.GroupLayout;
+import javax.swing.GroupLayout.ParallelGroup;
+import javax.swing.GroupLayout.SequentialGroup;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IServices;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerAdmin;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class Services extends javax.swing.JFrame
+{
+    private ArrayList<buttonNlabel> listbuttons;
+    private static Semaphore sem = new Semaphore(1, true);
+    private static Services instance = null;
+    private static IServices serv;
+    private static IPluginControllerAdmin plugin;
+    //private static INetworkInterfaces networkInterfaces;
+    private ImageIcon startIcon = new ImageIcon(Thread.currentThread().getContextClassLoader().getResource("playSmall.png"));
+    private ImageIcon stopIcon = new ImageIcon(Thread.currentThread().getContextClassLoader().getResource("stopSmall.png"));
+
+    
+    
+     public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+    
+    private class buttonNlabel
+    {
+
+        private JButton button;
+        private JLabel label;
+        private JLabel labelName;
+        private IPluginControllerAdmin pluginController;
+
+        
+        
+        public buttonNlabel(boolean isRunning, String labelName)
+        {
+            this.pluginController = AdminRefs.getInstance().getPluginController();
+
+            this.labelName = new JLabel();
+            this.labelName.setText(labelName);
+
+            this.label = new JLabel();
+
+            this.button = new JButton();
+
+            if (isRunning)
+            {
+                label.setText("Running");
+                button.setText("Stop");
+                button.setIcon(stopIcon);
+            } else
+            {
+                label.setText("Stopped");
+                button.setText("Start");
+                button.setIcon(startIcon);
+            }
+            button.addActionListener(new java.awt.event.ActionListener()
+            {
+
+                @Override
+                public void actionPerformed(java.awt.event.ActionEvent evt)
+                {
+                    buttonActionPerformed(evt);
+                }
+            });
+        }
+
+        private void buttonActionPerformed(java.awt.event.ActionEvent evt)
+        {
+            try
+            {
+                if (this.pluginController.isRunning(this.labelName.getText()))
+                {
+                    this.pluginController.StopPlugin(this.labelName.getText());
+                } else
+                {
+                    this.pluginController.InitiatePlugin(this.labelName.getText());
+                }
+                refreshInterface();
+            } catch (RemoteException ex)
+            {
+                LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+            }
+        }
+
+        /* public void setIsRunning(boolean isRunning)
+        {
+        if (isRunning)
+        {
+        label.setText("Running");
+        button.setText("Stop");
+        button.setIcon(stopIcon);
+        } else
+        {
+        label.setText("Stopped");
+        button.setText("Start");
+        button.setIcon(startIcon);
+        }
+        }*/
+        public void refresh()
+        {
+            try
+            {
+                if (this.pluginController.isRunning(this.labelName.getText()))
+                {
+                    label.setText("Running");
+                    button.setText("Stop");
+                    button.setIcon(stopIcon);
+                } else
+                {
+                    label.setText("Stopped");
+                    button.setText("Start");
+                    button.setIcon(startIcon);
+                }
+            } catch (RemoteException ex)
+            {
+                LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+            }
+        }
+
+        public JButton getButton()
+        {
+            return button;
+        }
+
+        public JLabel getLabel()
+        {
+            return label;
+        }
+
+        public JLabel getLabelName()
+        {
+            return labelName;
+        }
+
+
+    }
+    
+
+    public static synchronized Services getInstance()
+    {
+        try
+        {
+            sem.acquire();
+            if (instance == null)
+            {
+                instance = new Services();
+            }
+            sem.release();
+        } catch (InterruptedException ex)
+        {
+//            LoggerFactory.getLogger(MainWindow.class.getName()).log(Level.FATAL, null, ex);
+        }
+        return instance;
+    }
+
+    /** Creates new form Services */
+    private Services()
+    {
+        plugin = AdminRefs.getInstance().getPluginController();
+        List<String> names = null;
+        try
+        {
+            names = plugin.getPluginNames();
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }
+
+        this.listbuttons = new ArrayList<buttonNlabel>();
+        if(names != null)
+        {
+            for(String pluginName: names)
+            {
+                try
+                {
+                    this.listbuttons.add(new buttonNlabel(plugin.isRunning(pluginName), pluginName));
+                } catch (RemoteException ex)
+                {
+                    LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+                }
+            }
+        }
+
+        initComponents();
+
+        javax.swing.GroupLayout jPanel4Layout = (GroupLayout) jPanel4.getLayout();
+        javax.swing.GroupLayout jPanel5Layout = (GroupLayout) jPanel5.getLayout();
+        javax.swing.GroupLayout jPanel2Layout = (GroupLayout) jPanel2.getLayout();
+
+        ParallelGroup buttonsH = jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jButtonQR)
+                    .addComponent(jButtonStorage)
+                    .addComponent(jButtonWeb)
+                    .addComponent(jButtonWebServices);
+        SequentialGroup buttonsV = jPanel4Layout.createSequentialGroup()
+                .addComponent(jButtonStorage)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jButtonQR)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonWeb)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonWebServices);
+
+        ParallelGroup namesH = jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel1)
+                    .addComponent(jLabel5)
+                    .addComponent(jLabel6)
+                    .addComponent(jLabel7);
+        SequentialGroup namesV = jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel5)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel6)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel7);
+
+        ParallelGroup statesH = jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                .addComponent(jLabel8, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel9, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel10, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel11, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE);
+        SequentialGroup statesV = jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel8)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jLabel9)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel10)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel11);
+
+        for(buttonNlabel bNl : this.listbuttons)
+        {
+            buttonsH.addComponent(bNl.getButton());
+            buttonsV.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(bNl.getButton());
+
+            namesH.addComponent(bNl.getLabelName());
+            namesV.addGap(18, 18, 18).addComponent(bNl.getLabelName());
+
+            statesH.addComponent(bNl.getLabel());
+            statesV.addGap(18, 18, 18).addComponent(bNl.getLabel());
+        }
+
+        jPanel4Layout.setHorizontalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(buttonsH)
+                .addContainerGap(16, Short.MAX_VALUE)));
+        
+        jPanel4Layout.setVerticalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(buttonsV.addContainerGap(51, Short.MAX_VALUE)));
+
+        jPanel5Layout.setHorizontalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(namesH)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        jPanel5Layout.setVerticalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(namesV.addContainerGap(71, Short.MAX_VALUE))
+        );
+
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(statesH)
+                .addContainerGap())
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(statesV.addContainerGap(71, Short.MAX_VALUE))
+        );
+
+        Services.serv = AdminRefs.getInstance().getServices();
+      //  Services.networkInterfaces = AdminRefs.getInstance().getNetworkInterfaces();
+        Services.plugin = AdminRefs.getInstance().getPluginController();
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        refreshInterface();
+    }
+
+    /**
+     * Refresh buttons and labels
+     * with current running services
+     *
+     */
+    private void refreshInterface()
+    {
+        try
+        {
+            if (serv.storageIsRunning())
+            {
+                jLabel8.setText("Running");
+                jButtonStorage.setText("Stop");
+                jButtonStorage.setIcon(stopIcon);
+            } else
+            {
+                jLabel8.setText("Stopped");
+                jButtonStorage.setText("Start");
+                jButtonStorage.setIcon(startIcon);
+            }
+            if (serv.queryRetrieveIsRunning())
+            {
+                jLabel9.setText("Running");
+                jButtonQR.setText("Stop");
+                jButtonQR.setIcon(stopIcon);
+            } else
+            {
+                jLabel9.setText("Stopped");
+                jButtonQR.setText("Start");
+                jButtonQR.setIcon(startIcon);
+            }
+            if (serv.webServerIsRunning())
+            {
+                jLabel10.setText("Running");
+                jButtonWeb.setText("Stop");
+                jButtonWeb.setIcon(stopIcon);
+            } else
+            {
+                jLabel10.setText("Stopped");
+                jButtonWeb.setText("Start");
+                jButtonWeb.setIcon(startIcon);
+            }
+            if (serv.webServicesIsRunning())
+            {
+                jLabel11.setText("Running");
+                jButtonWebServices.setText("Stop");
+                jButtonWebServices.setIcon(stopIcon);
+            } else
+            {
+                jLabel11.setText("Stopped");
+                jButtonWebServices.setText("Start");
+                jButtonWebServices.setIcon(startIcon);
+            }
+
+            for (buttonNlabel b : this.listbuttons)
+            {
+                b.refresh();
+            }
+            /*            if (serv.p2PIsRunning()) {
+            jLabel13.setText("Running");
+            jButtonP2P.setText("Stop");
+            jButtonP2P.setIcon(stopIcon);
+            } else {
+            jLabel13.setText("Stopped");
+            jButtonP2P.setText("Start");
+            jButtonP2P.setIcon(startIcon);
+            }*/
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }
+        //Updates allways the members list.
+    /*    jComboBox1.removeAllItems();
+        try
+        {
+            for (String networkInterface : networkInterfaces.getNetworkInterfaces())
+            {
+                jComboBox1.addItem(networkInterface);
+            }
+            if (networkInterfaces.getNetworkInterface() != null)
+            {
+                this.jComboBox1.setSelectedItem(networkInterfaces.getNetworkInterface());
+            }
+               if(networkInterfaces.getNetworkInterface() == null)
+            networkInterfaces.setNetworkInterface((String) this.jComboBox1.getSelectedItem());
+            else
+            {
+            System.out.println(networkInterfaces.getNetworkInterface());
+            this.jComboBox1.setSelectedItem(networkInterfaces.getNetworkInterface());
+            }
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }*/
+    }
+
+    private void showOptions()
+    {
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jPanel1 = new javax.swing.JPanel();
+        jSeparator1 = new javax.swing.JSeparator();
+        jPanel2 = new javax.swing.JPanel();
+        jLabel8 = new javax.swing.JLabel();
+        jLabel9 = new javax.swing.JLabel();
+        jLabel10 = new javax.swing.JLabel();
+        jLabel11 = new javax.swing.JLabel();
+        jPanel3 = new javax.swing.JPanel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jLabel4 = new javax.swing.JLabel();
+        jPanel5 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        jLabel6 = new javax.swing.JLabel();
+        jLabel7 = new javax.swing.JLabel();
+        jPanel4 = new javax.swing.JPanel();
+        jButtonStorage = new javax.swing.JButton();
+        jButtonQR = new javax.swing.JButton();
+        jButtonWeb = new javax.swing.JButton();
+        jButtonWebServices = new javax.swing.JButton();
+        jPanel6 = new javax.swing.JPanel();
+        jButtonQRStorageServers = new javax.swing.JButton();
+        jLabel12 = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Dicoogle Services");
+        setResizable(false);
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        jLabel8.setText("status");
+
+        jLabel9.setText("status");
+
+        jLabel10.setText("status");
+
+        jLabel11.setText("status");
+
+        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
+        jPanel2.setLayout(jPanel2Layout);
+        jPanel2Layout.setHorizontalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel8, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel9, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel10, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE)
+                    .addComponent(jLabel11, javax.swing.GroupLayout.DEFAULT_SIZE, 90, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        jPanel2Layout.setVerticalGroup(
+            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel2Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel8)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jLabel9)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel10)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel11)
+                .addContainerGap(76, Short.MAX_VALUE))
+        );
+
+        jLabel8.getAccessibleContext().setAccessibleName("storageStatusLabel");
+
+        jLabel2.setText("Service");
+
+        jLabel3.setText("Status");
+
+        jLabel4.setText("Control");
+
+        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
+        jPanel3.setLayout(jPanel3Layout);
+        jPanel3Layout.setHorizontalGroup(
+            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel3Layout.createSequentialGroup()
+                .addGap(24, 24, 24)
+                .addComponent(jLabel2)
+                .addGap(90, 90, 90)
+                .addComponent(jLabel3)
+                .addGap(72, 72, 72)
+                .addComponent(jLabel4)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        jPanel3Layout.setVerticalGroup(
+            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel3Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(jLabel2)
+                    .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(jLabel4))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jLabel1.setText("DICOM Storage:");
+
+        jLabel5.setText("DICOM Query/Retrieve:");
+
+        jLabel6.setText("Dicoogle Web:");
+
+        jLabel7.setText("Dicoogle WebServices:");
+
+        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
+        jPanel5.setLayout(jPanel5Layout);
+        jPanel5Layout.setHorizontalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel1)
+                    .addComponent(jLabel5)
+                    .addComponent(jLabel6)
+                    .addComponent(jLabel7))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        jPanel5Layout.setVerticalGroup(
+            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel5Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(jLabel5)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel6)
+                .addGap(18, 18, 18)
+                .addComponent(jLabel7)
+                .addContainerGap(76, Short.MAX_VALUE))
+        );
+
+        jButtonStorage.setIcon(new ImageIcon(getImage("playSmall.png")));
+        jButtonStorage.setText("Start");
+        jButtonStorage.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonStorageActionPerformed(evt);
+            }
+        });
+
+        jButtonQR.setIcon(new ImageIcon(getImage("playSmall.png")));
+        jButtonQR.setText("Start");
+        jButtonQR.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonQRActionPerformed(evt);
+            }
+        });
+
+        jButtonWeb.setIcon(new ImageIcon(getImage("playSmall.png")));
+        jButtonWeb.setText("Start");
+        jButtonWeb.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonWebActionPerformed(evt);
+            }
+        });
+
+        jButtonWebServices.setIcon(new ImageIcon(getImage("playSmall.png")));
+        jButtonWebServices.setText("Start");
+        jButtonWebServices.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonWebServicesActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel4Layout = new javax.swing.GroupLayout(jPanel4);
+        jPanel4.setLayout(jPanel4Layout);
+        jPanel4Layout.setHorizontalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jButtonQR)
+                    .addComponent(jButtonStorage)
+                    .addComponent(jButtonWeb)
+                    .addComponent(jButtonWebServices))
+                .addContainerGap(16, Short.MAX_VALUE))
+        );
+        jPanel4Layout.setVerticalGroup(
+            jPanel4Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel4Layout.createSequentialGroup()
+                .addComponent(jButtonStorage)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonQR)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonWeb)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jButtonWebServices)
+                .addContainerGap(60, Short.MAX_VALUE))
+        );
+
+        jButtonQRStorageServers.setIcon(new ImageIcon(getImage("data-server.png")));
+        jButtonQRStorageServers.setText("Storage Servers");
+        jButtonQRStorageServers.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonQRStorageServersActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
+        jPanel6.setLayout(jPanel6Layout);
+        jPanel6Layout.setHorizontalGroup(
+            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel6Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jButtonQRStorageServers)
+                .addContainerGap(111, Short.MAX_VALUE))
+        );
+        jPanel6Layout.setVerticalGroup(
+            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel6Layout.createSequentialGroup()
+                .addGap(31, 31, 31)
+                .addComponent(jButtonQRStorageServers)
+                .addContainerGap(113, Short.MAX_VALUE))
+        );
+
+        jLabel12.setText("To define Dicoogle Inicial Services go to: Preferences -> Inicial Services");
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSeparator1)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addGap(27, 27, 27)
+                .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGap(6, 6, 6)
+                        .addComponent(jPanel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addGap(7, 7, 7)
+                        .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(jLabel12)))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 12, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                            .addComponent(jPanel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 26, Short.MAX_VALUE)
+                        .addComponent(jLabel12)
+                        .addGap(9, 9, 9))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addContainerGap())))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(9, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+        MainWindow main = MainWindow.getInstance();
+
+        main.toFront();
+        main.setEnabled(true);
+
+        this.dispose();
+    }//GEN-LAST:event_formWindowClosing
+
+    private void jButtonStorageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonStorageActionPerformed
+        try
+        {
+            if (serv.storageIsRunning())
+            {
+                serv.stopStorage();
+            } else
+            {
+                try
+                {
+                    if (serv.startStorage() == -1)
+                    {
+                        int choice = JOptionPane.showConfirmDialog(null, "The server's storage path is not defined. Do you wish to define it?", "Error: Undefined Storage Path", JOptionPane.YES_NO_OPTION);
+                        if (choice == 0)
+                        {
+                            showOptions();
+                        }
+                    }
+                } catch (IOException ex)
+                {
+                    LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+                }
+            }
+            refreshInterface();
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonStorageActionPerformed
+
+    private void jButtonQRActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonQRActionPerformed
+        try
+        {
+            if (serv.queryRetrieveIsRunning())
+            {
+                serv.stopQueryRetrieve();
+            } else
+            {
+                serv.startQueryRetrieve();
+            }
+            refreshInterface();
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonQRActionPerformed
+
+    private void jButtonWebActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonWebActionPerformed
+        try
+        {
+            if (serv.webServerIsRunning())
+            {
+                serv.stopWebServer();
+            } else
+            {
+                serv.startWebServer();
+            }
+            refreshInterface();
+        } catch (RemoteException ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }       
+        
+    }//GEN-LAST:event_jButtonWebActionPerformed
+
+    private void jButtonWebServicesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonWebServicesActionPerformed
+        try
+        {
+            if (serv.webServicesIsRunning())
+            {
+                serv.stopWebServices();
+            } else
+            {
+                serv.startWebServices();
+            }
+
+        } catch (Exception ex)
+        {
+            LoggerFactory.getLogger(Services.class).error(ex.getMessage(), ex);
+        }
+        refreshInterface();
+    }//GEN-LAST:event_jButtonWebServicesActionPerformed
+
+    private void jButtonQRStorageServersActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonQRStorageServersActionPerformed
+        QRServers QRservers = QRServers.getInstance();
+        QRservers.setVisible(true);
+        QRservers.toFront();
+    }//GEN-LAST:event_jButtonQRStorageServersActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonQR;
+    private javax.swing.JButton jButtonQRStorageServers;
+    private javax.swing.JButton jButtonStorage;
+    private javax.swing.JButton jButtonWeb;
+    private javax.swing.JButton jButtonWebServices;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel10;
+    private javax.swing.JLabel jLabel11;
+    private javax.swing.JLabel jLabel12;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel6;
+    private javax.swing.JLabel jLabel7;
+    private javax.swing.JLabel jLabel8;
+    private javax.swing.JLabel jLabel9;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JPanel jPanel2;
+    private javax.swing.JPanel jPanel3;
+    private javax.swing.JPanel jPanel4;
+    private javax.swing.JPanel jPanel5;
+    private javax.swing.JPanel jPanel6;
+    private javax.swing.JSeparator jSeparator1;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.form
new file mode 100755
index 0000000..1cb62f7
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.form
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
+    <Property name="axis" type="int" value="1"/>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Task Progress"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JSeparator" name="jSeparator1">
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.java
new file mode 100755
index 0000000..8c6916c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/TaskList.java
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*
+ * 
+ * 
+ * TaskList.java
+ *
+ * Created on Jul 20, 2010, 10:21:21 AM
+ */
+
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import javax.swing.JProgressBar;
+import javax.swing.Timer;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ITaskList;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ITaskListSignal;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public final class TaskList extends javax.swing.JPanel {
+
+    private static ITaskList taskList;
+    private static ITaskListSignal tasksSignal;
+
+    class PairTaskProgress{
+        public Task task;
+        public JProgressBar bar;
+    }
+    private ArrayList<PairTaskProgress> tasks = new ArrayList<>();
+    
+    Timer timer;
+    
+    /** Creates new form TaskList */
+    public TaskList(){
+        initComponents();
+        
+        ActionListener updateTask = new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                updateProgress();
+            }
+        };
+        
+        timer = new Timer(1000,updateTask);
+        timer.start();
+        
+        //registerRemoteObject();
+        //getTaskList();
+
+    }
+
+    public void updateProgress(){
+        ArrayList<PairTaskProgress> ntasks = new ArrayList<>();
+        for(PairTaskProgress task : tasks){
+            //otherwise updates it
+           task.bar.setValue((int)(task.task.getProgress()*100));
+            if(task.task.isDone()){
+                remove(task.bar);
+            }
+            else{
+                ntasks.add(task);
+            }
+        }
+        tasks = ntasks;
+        
+        revalidate();
+        repaint();
+    }
+    
+    public void add(Iterable<Task<Report>> tasks){
+                
+        for(Task<Report> task : tasks){
+            JProgressBar bar = new JProgressBar(0,100);
+            bar.setString(task.getName()+" -> "+task.getProgress());
+            bar.setValue((int)(task.getProgress()*100)+10);
+            
+            PairTaskProgress pair = new PairTaskProgress();
+            pair.task = task;
+            pair.bar = bar;
+            //scrollPanel.add(pair.bar);
+            this.tasks.add(pair);
+            add(bar);
+
+        }
+        updateProgress();
+    }
+    
+
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jSeparator1 = new javax.swing.JSeparator();
+
+        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
+
+        jLabel1.setText("Task Progress");
+        add(jLabel1);
+        add(jSeparator1);
+    }// </editor-fold>//GEN-END:initComponents
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JSeparator jSeparator1;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.form
new file mode 100755
index 0000000..e10d924
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.form
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[413, 223]"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="1" attributes="0">
+                      <Component id="jButtonAdd" min="-2" max="-2" attributes="1"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonRemove" min="-2" pref="118" max="-2" attributes="1"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonReset" min="-2" pref="118" max="-2" attributes="1"/>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jButtonWrite" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" alignment="1" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Group type="102" alignment="0" attributes="0">
+                                  <Group type="103" groupAlignment="0" attributes="0">
+                                      <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                                  <EmptySpace min="-2" pref="24" max="-2" attributes="0"/>
+                                  <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                                      <Component id="jCheckBox" alignment="0" max="32767" attributes="1"/>
+                                      <Component id="jPasswordField" alignment="0" max="32767" attributes="1"/>
+                                      <Component id="jTextUsername" alignment="0" min="-2" pref="152" max="-2" attributes="1"/>
+                                  </Group>
+                              </Group>
+                              <Component id="jSeparator1" alignment="1" min="-2" pref="264" max="-2" attributes="1"/>
+                          </Group>
+                          <Component id="jCheckBoxEncrypt" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="38" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jScrollPane1" alignment="0" min="-2" pref="195" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace pref="14" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
+              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jTextUsername" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel3" min="-2" max="-2" attributes="0"/>
+                          <Component id="jPasswordField" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Component id="jCheckBox" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                      <Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                      <Component id="jCheckBoxEncrypt" min="-2" max="-2" attributes="0"/>
+                      <EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
+                  </Group>
+                  <Group type="102" attributes="0">
+                      <Component id="jScrollPane1" min="-2" pref="181" max="-2" attributes="0"/>
+                      <EmptySpace max="32767" attributes="0"/>
+                  </Group>
+              </Group>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jButtonRemove" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonReset" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonWrite" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jButtonAdd" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="jScrollPane1">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JList" name="jListUsers">
+          <Properties>
+            <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
+              <StringArray count="0"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="jListUsersValueChanged"/>
+          </Events>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JList(modelUsers)"/>
+            <AuxValue name="JavaCodeGenerator_CreateCodePre" type="java.lang.String" value="DefaultListModel modelUsers = new DefaultListModel();"/>
+          </AuxValues>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="List of Users:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonAdd">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("add.png"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Add User"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonAddActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonRemove">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("remove.png"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Remove User"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonRemoveActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Username:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel3">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Password:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JCheckBox" name="jCheckBox">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Administrator"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="jTextUsername">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jTextUsernameKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JPasswordField" name="jPasswordField">
+      <Events>
+        <EventHandler event="keyPressed" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="jPasswordFieldKeyPressed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonWrite">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("floopy-icon.png"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Save Configurations"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonWriteActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JCheckBox" name="jCheckBoxEncrypt">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Encrypt the users file"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jCheckBoxEncryptActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JSeparator" name="jSeparator1">
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonReset">
+      <Properties>
+        <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="new ImageIcon(getImage("reset.png"))" type="code"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Reset Pass"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonResetActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.java
new file mode 100755
index 0000000..c270977
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/client/windows/UsersManager.java
@@ -0,0 +1,406 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * UsersManager.java
+ *
+ * Created on 6/Abr/2010, 14:07:58
+ */
+package pt.ua.dicoogle.rGUI.client.windows;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.net.URL;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.rGUI.client.AdminRefs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IUsersManager;
+import pt.ua.dicoogle.server.users.HashService;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at Deprecated
+public class UsersManager extends javax.swing.JFrame {
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static UsersManager instance = null;
+    private IUsersManager userManager;
+
+    public static synchronized UsersManager getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new UsersManager();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+    public static Image getImage(final String pathAndFileName) {
+        final URL url = Thread.currentThread().getContextClassLoader().getResource(pathAndFileName);
+        return Toolkit.getDefaultToolkit().getImage(url);
+    }
+    
+
+    /** Creates new form UsersManager */
+    private UsersManager() {
+        initComponents();
+
+        userManager = AdminRefs.getInstance().getUsersManager();
+
+        load();
+        
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        this.setTitle("User Accounts");
+
+        jButtonRemove.setEnabled(false);
+        jButtonReset.setEnabled(false);
+    }
+
+    private void load() {
+        try {
+            DefaultListModel model = (DefaultListModel) jListUsers.getModel();
+            model.clear();
+
+            ArrayList<String> list = userManager.getUsernames();
+            
+            for (int i = 0; i < list.size(); i++)
+                model.addElement(list.get(i));
+
+            jListUsers.setModel(model);
+
+            jCheckBoxEncrypt.setSelected(userManager.getEncryptUsersFile());
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        DefaultListModel modelUsers = new DefaultListModel();
+        jListUsers = new javax.swing.JList(modelUsers);
+        jLabel1 = new javax.swing.JLabel();
+        jButtonAdd = new javax.swing.JButton();
+        jButtonRemove = new javax.swing.JButton();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        jCheckBox = new javax.swing.JCheckBox();
+        jTextUsername = new javax.swing.JTextField();
+        jPasswordField = new javax.swing.JPasswordField();
+        jButtonWrite = new javax.swing.JButton();
+        jCheckBoxEncrypt = new javax.swing.JCheckBox();
+        jSeparator1 = new javax.swing.JSeparator();
+        jButtonReset = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setMinimumSize(new java.awt.Dimension(413, 223));
+
+        jListUsers.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
+            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
+                jListUsersValueChanged(evt);
+            }
+        });
+        jScrollPane1.setViewportView(jListUsers);
+
+        jLabel1.setText("List of Users:");
+
+        jButtonAdd.setIcon(new ImageIcon(getImage("add.png")));
+        jButtonAdd.setText("Add User");
+        jButtonAdd.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonAddActionPerformed(evt);
+            }
+        });
+
+        jButtonRemove.setIcon(new ImageIcon(getImage("remove.png")));
+        jButtonRemove.setText("Remove User");
+        jButtonRemove.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonRemoveActionPerformed(evt);
+            }
+        });
+
+        jLabel2.setText("Username:");
+
+        jLabel3.setText("Password:");
+
+        jCheckBox.setText("Administrator");
+
+        jTextUsername.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jTextUsernameKeyPressed(evt);
+            }
+        });
+
+        jPasswordField.addKeyListener(new java.awt.event.KeyAdapter() {
+            public void keyPressed(java.awt.event.KeyEvent evt) {
+                jPasswordFieldKeyPressed(evt);
+            }
+        });
+
+        jButtonWrite.setIcon(new ImageIcon(getImage("floopy-icon.png")));
+        jButtonWrite.setText("Save Configurations");
+        jButtonWrite.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonWriteActionPerformed(evt);
+            }
+        });
+
+        jCheckBoxEncrypt.setText("Encrypt the users file");
+        jCheckBoxEncrypt.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jCheckBoxEncryptActionPerformed(evt);
+            }
+        });
+
+        jButtonReset.setIcon(new ImageIcon(getImage("reset.png")));
+        jButtonReset.setText("Reset Pass");
+        jButtonReset.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonResetActionPerformed(evt);
+            }
+        });
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(15, 15, 15)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(jButtonAdd)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonRemove, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 118, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonReset, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 118, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jButtonWrite))
+                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                .add(layout.createSequentialGroup()
+                                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                                        .add(jLabel2)
+                                        .add(jLabel3))
+                                    .add(24, 24, 24)
+                                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
+                                        .add(jCheckBox, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                                        .add(jPasswordField)
+                                        .add(jTextUsername, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 152, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
+                                .add(org.jdesktop.layout.GroupLayout.TRAILING, jSeparator1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 264, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                            .add(jCheckBoxEncrypt))
+                        .add(38, 38, 38)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel1)
+                            .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 195, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
+                .addContainerGap(14, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(13, 13, 13)
+                .add(jLabel1)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                            .add(jLabel2)
+                            .add(jTextUsername, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                        .add(2, 2, 2)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel3)
+                            .add(jPasswordField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                        .add(jCheckBox)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 39, Short.MAX_VALUE)
+                        .add(jSeparator1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                        .add(jCheckBoxEncrypt)
+                        .add(30, 30, 30))
+                    .add(layout.createSequentialGroup()
+                        .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 181, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jButtonRemove)
+                    .add(jButtonReset)
+                    .add(jButtonWrite)
+                    .add(jButtonAdd))
+                .add(20, 20, 20))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jListUsersValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_jListUsersValueChanged
+        try {
+            if(!jListUsers.isSelectionEmpty()){
+                String username = (String) jListUsers.getSelectedValue();
+                jTextUsername.setText(username);
+
+                jCheckBox.setSelected(userManager.isAdmin(username));
+                
+                jCheckBox.setEnabled(false);
+                //jPasswordField.setEnabled(false);
+                jButtonAdd.setEnabled(false);
+                jButtonRemove.setEnabled(true);
+            }
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jListUsersValueChanged
+
+    private void jTextUsernameKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextUsernameKeyPressed
+        jCheckBox.setEnabled(true);
+        jPasswordField.setEnabled(true);
+        jButtonAdd.setEnabled(true);
+        jButtonRemove.setEnabled(false);
+        jButtonReset.setEnabled(false);
+        jListUsers.clearSelection();
+    }//GEN-LAST:event_jTextUsernameKeyPressed
+
+    private void jButtonAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonAddActionPerformed
+        try {
+            String passPlainText = new String(jPasswordField.getPassword());
+
+            if (passPlainText.length() == 0){
+                JOptionPane.showMessageDialog(this, "Password must have characters!",
+                    "Password Empty", JOptionPane.INFORMATION_MESSAGE);
+
+                return;
+            }
+
+            String passHash = HashService.getSHA1Hash(passPlainText);
+
+            if(!userManager.addUser(jTextUsername.getText(), passHash, jCheckBox.isSelected()))
+                JOptionPane.showMessageDialog(this, "Username already exists or invalid username or password!",
+                    "Error Adding User", JOptionPane.ERROR_MESSAGE);
+
+            load();
+            
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonAddActionPerformed
+
+    private void jButtonRemoveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonRemoveActionPerformed
+        try {
+            if (!userManager.deleteUser(jTextUsername.getText())) {
+                JOptionPane.showMessageDialog(this, "Username doesn't exists or this user is the last administrator!", "Error Removing User", JOptionPane.ERROR_MESSAGE);
+            }
+
+            jCheckBox.setEnabled(true);
+            jPasswordField.setEnabled(true);
+            jButtonAdd.setEnabled(true);
+            jButtonRemove.setEnabled(false);
+            jButtonReset.setEnabled(false);
+            jListUsers.clearSelection();
+            
+            load();
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonRemoveActionPerformed
+
+    private void jButtonWriteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonWriteActionPerformed
+        AdminRefs.getInstance().saveSettings();
+}//GEN-LAST:event_jButtonWriteActionPerformed
+
+    private void jCheckBoxEncryptActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxEncryptActionPerformed
+        try {
+            userManager.setEncryptUsersFile(jCheckBoxEncrypt.isSelected());
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jCheckBoxEncryptActionPerformed
+
+    private void jButtonResetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonResetActionPerformed
+        try {
+            String passPlainText = new String(jPasswordField.getPassword());
+            
+            if (passPlainText.length() == 0) {
+                JOptionPane.showMessageDialog(this, "Password must have characters!", "Password Empty", JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+            
+            String passHash = HashService.getSHA1Hash(passPlainText);
+            
+            if (!userManager.resetPassword(jTextUsername.getText(), passHash)) {
+                JOptionPane.showMessageDialog(this, "Password was not changed!", "Error Reseting Password", JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+
+            JOptionPane.showMessageDialog(this, "Password successfully changed!", "Password Reseted", JOptionPane.INFORMATION_MESSAGE);
+            
+            jCheckBox.setEnabled(true);
+            jPasswordField.setEnabled(true);
+            jButtonAdd.setEnabled(true);
+            jButtonRemove.setEnabled(false);
+            jButtonReset.setEnabled(false);
+            jListUsers.clearSelection();
+
+        } catch (RemoteException ex) {
+            LoggerFactory.getLogger(UsersManager.class).error(ex.getMessage(), ex);
+        }
+    }//GEN-LAST:event_jButtonResetActionPerformed
+
+    private void jPasswordFieldKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jPasswordFieldKeyPressed
+        if(jListUsers.getSelectedValue() != null){
+            jButtonReset.setEnabled(true);
+        }
+    }//GEN-LAST:event_jPasswordFieldKeyPressed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonAdd;
+    private javax.swing.JButton jButtonRemove;
+    private javax.swing.JButton jButtonReset;
+    private javax.swing.JButton jButtonWrite;
+    private javax.swing.JCheckBox jCheckBox;
+    private javax.swing.JCheckBox jCheckBoxEncrypt;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JList jListUsers;
+    private javax.swing.JPasswordField jPasswordField;
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JTextField jTextUsername;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileReceiver.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileReceiver.java
new file mode 100755
index 0000000..99e30e3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileReceiver.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.fileTransfer;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+import pt.ua.dicoogle.core.ClientSettings;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class FileReceiver extends Thread {
+    private RemoteFile file;
+    private InetAddress serverAddr;
+    private int serverPort;
+    private TransferStatus ts;
+
+    private Socket socket;
+
+    private String filePath;
+
+    public FileReceiver(RemoteFile file, InetAddress serverAddr, int serverPort, TransferStatus ts) throws IOException{
+        SocketFactory socketFactory = SSLSocketFactory.getDefault();
+        socket = socketFactory.createSocket(serverAddr, serverPort);
+
+        this.file = file;
+        this.serverAddr = serverAddr;
+        this.serverPort = serverPort;
+        this.ts = ts;
+
+        String dirPath = ClientSettings.getInstance().getTempFilesDir();
+
+        //if the temporary folder is not defined
+        if (dirPath == null || dirPath.equals(""))
+            dirPath = ".";
+
+        filePath = dirPath + "/" + file.getName();
+        ts.setFilePath(filePath);
+    }
+
+    @Override
+    public void run(){
+        //DebugManager.getInstance().debug("Starting transfer Thread...");
+
+        long sizeTransfered = receiver();
+
+        if(sizeTransfered != -1)
+            //DebugManager.getInstance().debug("Transfer complete! File: " + file.getName());
+
+        return;
+    }
+
+    public String getFilePath(){
+        return filePath;
+    }
+
+    private long receiver(){
+        long transferedBytes = 0;
+
+        try{
+            // Buffer size = 1 KB
+            byte data[] = new byte[1024];
+
+            InputStream in = socket.getInputStream();
+            FileOutputStream out = new FileOutputStream(filePath);
+
+            int size;
+            // write in file
+            while ((size = in.read(data)) != -1){
+                transferedBytes += size;
+
+                out.write(data, 0, size);
+		out.flush();
+
+                // refresh the progress bar
+                if(ts != null)
+                    ts.setTransferedBytes(transferedBytes);
+            }
+
+            // Freeing resources
+            out.close();
+            in.close();
+            socket.close();
+
+        } catch (IOException ex) {
+            ts.errorInTransfer("There was an error downloading the file!");
+
+            try {
+                if (!socket.isClosed())
+                    socket.close();
+            } catch (IOException e) {
+                LoggerFactory.getLogger(FileReceiver.class).error(ex.getMessage(), e);
+            }
+
+            //LoggerFactory.getLogger(FileSender.class).error(ex.getMessage(), ex);
+            return -1;
+        }
+
+        return transferedBytes;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileSender.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileSender.java
new file mode 100755
index 0000000..d49bb19
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/FileSender.java
@@ -0,0 +1,156 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.fileTransfer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class FileSender extends Thread {
+    private File file;
+    private InetAddress client;
+    private int timeout = 2000; //2 seconds of timeout
+
+    private ServerSocket ssocket;
+    private Socket socket;
+
+    public FileSender(File file, InetAddress client) throws IOException{
+        ServerSocketFactory ssocketFactory = SSLServerSocketFactory.getDefault();
+        ssocket = ssocketFactory.createServerSocket();
+        ssocket.bind(null);
+        ssocket.setSoTimeout(timeout);
+
+        this.file = file;
+        this.client = client;
+    }
+
+    @Override
+    public void run(){
+        long sizeTransfered;
+
+        try {
+            sizeTransfered = sender();
+            
+            //if(sizeTransfered != -1)
+               // DebugManager.getInstance().debug("Transfer complete! File: " + file.getName());
+            //else
+                //(DebugManager.getInstance().debug("There was an error transfering the file: " + file.getName());
+
+        } catch (IllegalAccessException ex) {
+            LoggerFactory.getLogger(FileSender.class).error(ex.getMessage(), ex);
+        }
+        
+        return;
+    }
+
+    /**
+     *
+     * @return the listener port
+     */
+    public int getListenerPort(){
+        return ssocket.getLocalPort();
+    }
+
+
+    /**
+     *
+     * @return the number of bytes transfered or -1 in error case
+     * @throws IllegalAccessException
+     */
+    private long sender() throws IllegalAccessException{
+        long transferedBytes = 0;
+        byte data[] = new byte[1024];
+
+        try {
+            try{
+                socket = ssocket.accept();
+            } catch(SocketTimeoutException ex){
+                //DebugManager.getInstance().debug("Timeout Transfering File: " + file.getName());
+
+                return -1;
+            }
+
+            /*
+            boolean illegalAccess = true;
+
+            InetAddress[] all = InetAddress.getAllByName(client.getHostName());
+
+            for (int i = 0; i < all.length; i++){
+                if (socket.getInetAddress().equals(all[i])){
+                    illegalAccess = false;
+                    break;
+                }
+            }
+
+            if(illegalAccess && socket.getInetAddress().equals(InetAddress.getByName("0.0.0.0")))
+                illegalAccess = false;
+
+            if(illegalAccess){
+                ssocket.close();
+                socket.close();
+
+                throw new IllegalAccessException("The IP that tried to establish the connection is not the client!\n");
+            }
+            */
+            
+            ssocket.close();   // close the listening server socket
+
+            FileInputStream in = new FileInputStream(file);
+            OutputStream out = socket.getOutputStream();
+
+            // Transfer the file
+            int size;
+            while ((size = in.read(data)) != -1) {
+                transferedBytes += size;
+
+                out.write(data, 0, size);
+                out.flush();
+            }
+
+            // Freeing resources
+            out.close();
+            in.close();
+            socket.close();
+
+        } catch (Exception ex) {
+           // LoggerFactory.getLogger(FileSender.class).error(ex.getMessage(), ex);
+
+            return -1;
+        }
+
+        return transferedBytes;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.form b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.form
new file mode 100755
index 0000000..07553b1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.form
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="File Transfer"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="103" alignment="0" groupAlignment="1" attributes="0">
+                      <Component id="jButtonView" alignment="1" min="-2" max="-2" attributes="0"/>
+                      <Group type="103" alignment="1" groupAlignment="0" attributes="0">
+                          <Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jProgressBar" alignment="0" min="-2" pref="323" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <Component id="jLabelState" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" alignment="0" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="jLabelFileName" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabelFileSize" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="jLabelProgress" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace pref="41" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
+              <Component id="jLabelState" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelFileName" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelFileSize" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace pref="25" max="32767" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="jLabelProgress" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
+              <Component id="jProgressBar" min="-2" max="-2" attributes="0"/>
+              <EmptySpace type="unrelated" max="-2" attributes="0"/>
+              <Component id="jButtonView" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="jLabel1">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="File:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelFileName">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="<FileName>"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel2">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Size (Bytes):"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelFileSize">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="<FileSize>"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JProgressBar" name="jProgressBar">
+    </Component>
+    <Component class="javax.swing.JButton" name="jButtonView">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="View"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jButtonViewActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelState">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Downloading the file from the server.."/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabel4">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Lucida Grande" size="13" style="1"/>
+        </Property>
+        <Property name="text" type="java.lang.String" value="Progress:"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="jLabelProgress">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="<Progress>"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.java
new file mode 100755
index 0000000..d3cf37a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/fileTransfer/TransferStatus.java
@@ -0,0 +1,239 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.fileTransfer;
+
+import java.awt.Desktop;
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.File;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.ClientSettings;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class TransferStatus extends javax.swing.JFrame {
+
+    private RemoteFile file;
+    private String filePath;
+
+    /** Creates new form TransferStatus */
+    public TransferStatus(RemoteFile file) {
+        initComponents();
+        
+        Image image = Toolkit.getDefaultToolkit().getImage(Thread.currentThread().getContextClassLoader().getResource("trayicon.gif"));
+        this.setIconImage(image);
+
+        this.file = file;
+        jProgressBar.setMaximum((int) file.length());
+        jProgressBar.setMinimum(0);
+        jProgressBar.setValue(0);
+        jProgressBar.setStringPainted(true);
+
+        jButtonView.setEnabled(false);
+        jLabelFileName.setText(file.getName());
+        jLabelFileSize.setText(String.valueOf(file.length()));
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jLabel1 = new javax.swing.JLabel();
+        jLabelFileName = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabelFileSize = new javax.swing.JLabel();
+        jProgressBar = new javax.swing.JProgressBar();
+        jButtonView = new javax.swing.JButton();
+        jLabelState = new javax.swing.JLabel();
+        jLabel4 = new javax.swing.JLabel();
+        jLabelProgress = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("File Transfer");
+
+        jLabel1.setFont(new java.awt.Font("Lucida Grande", 1, 13));
+        jLabel1.setText("File:");
+
+        jLabelFileName.setText("<FileName>");
+
+        jLabel2.setFont(new java.awt.Font("Lucida Grande", 1, 13));
+        jLabel2.setText("Size (Bytes):");
+
+        jLabelFileSize.setText("<FileSize>");
+
+        jButtonView.setText("View");
+        jButtonView.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jButtonViewActionPerformed(evt);
+            }
+        });
+
+        jLabelState.setFont(new java.awt.Font("Lucida Grande", 1, 13)); // NOI18N
+        jLabelState.setText("Downloading the file from the server..");
+
+        jLabel4.setFont(new java.awt.Font("Lucida Grande", 1, 13));
+        jLabel4.setText("Progress:");
+
+        jLabelProgress.setText("<Progress>");
+
+        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(36, 36, 36)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                    .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
+                        .add(jButtonView)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel4)
+                            .add(jProgressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 323, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
+                    .add(jLabelState)
+                    .add(layout.createSequentialGroup()
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabel2)
+                            .add(jLabel1))
+                        .add(18, 18, 18)
+                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+                            .add(jLabelFileName)
+                            .add(jLabelFileSize)
+                            .add(jLabelProgress))))
+                .addContainerGap(41, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
+            .add(layout.createSequentialGroup()
+                .add(26, 26, 26)
+                .add(jLabelState)
+                .add(18, 18, 18)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel1)
+                    .add(jLabelFileName))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel2)
+                    .add(jLabelFileSize))
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 25, Short.MAX_VALUE)
+                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
+                    .add(jLabel4)
+                    .add(jLabelProgress))
+                .add(7, 7, 7)
+                .add(jProgressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
+                .add(jButtonView)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void jButtonViewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonViewActionPerformed
+        if (ClientSettings.getInstance().getExtV() == null
+                || ClientSettings.getInstance().getExtV().equals("")) {
+
+            try {
+                Desktop.getDesktop().open(new File(filePath));
+
+            } catch (IOException ex) {
+                String folder = filePath.substring(0, filePath.lastIndexOf('/'));
+
+                try {
+                    Desktop.getDesktop().open(new File(folder));
+
+                } catch (IOException ex1) {
+                    JOptionPane.showMessageDialog(this, "Dicoogle can't open this file!", "Error opening the file", JOptionPane.ERROR_MESSAGE);
+                }
+            }
+        } else {
+            try {
+                ProcessBuilder pb = new ProcessBuilder(ClientSettings.getInstance().getExtV(), filePath);
+                pb.start();
+
+            } catch (IOException ex) {
+
+                String folder = filePath.substring(0, filePath.lastIndexOf('/'));
+
+                try {
+                    Desktop.getDesktop().open(new File(folder));
+
+                } catch (IOException ex1) {
+                    JOptionPane.showMessageDialog(this, "Dicoogle can't open this file!", "Error opening the file", JOptionPane.ERROR_MESSAGE);
+                }
+            }
+        }
+    }//GEN-LAST:event_jButtonViewActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton jButtonView;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabelFileName;
+    private javax.swing.JLabel jLabelFileSize;
+    private javax.swing.JLabel jLabelProgress;
+    private javax.swing.JLabel jLabelState;
+    private javax.swing.JProgressBar jProgressBar;
+    // End of variables declaration//GEN-END:variables
+
+    public void setFilePath(String filePath){
+        this.filePath = filePath;
+    }
+
+    public void setTransferedBytes(long size){
+        long perc = (size * 100 / file.length());
+
+        jProgressBar.setValue((int) size);
+        jProgressBar.setString(String.valueOf(perc) + "%");
+
+
+        jLabelProgress.setText(String.valueOf(size));
+
+        if(size == file.length()){
+            jLabelState.setText("Download complete. Click 'View' button");
+
+            if(this.filePath != null)
+                jButtonView.setEnabled(true);
+        }
+    }
+
+    public void errorInTransfer(String error){
+        JOptionPane.showMessageDialog(this, error,
+                    "Transfer Error", JOptionPane.ERROR_MESSAGE);
+
+        //closes this window
+        this.dispatchEvent(new java.awt.event.WindowEvent(this,
+                java.awt.Event.WINDOW_DESTROY));
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IAdmin.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IAdmin.java
new file mode 100755
index 0000000..90497e0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IAdmin.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.interfaces;
+
+import pt.ua.dicoogle.rGUI.RFileBrowser.IRemoteFileSystem;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ILogs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IServices;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IStartupServ;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQRServers;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IAccessList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IActiveSessions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDirectory;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IIndexOptions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.INetworkInterfaces;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPendingMessages;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQueryRetrieve;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISOPClass;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ITaskList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IUsersManager;
+
+
+/**
+ * This interface contains methods that are features of administration
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IAdmin extends Remote {
+
+    //get the username of the current Administrator
+    public String getUsername() throws RemoteException;
+
+    public IUser getUser() throws RemoteException;
+
+    public IServices getServices() throws RemoteException;
+
+    public ILogs getLogs() throws RemoteException;
+
+    public IQRServers getQRServers() throws RemoteException;
+
+    public IStartupServ getStartupServ() throws RemoteException;
+
+    public IQueryRetrieve getQueryRetrive() throws RemoteException;
+
+    public IAccessList getAccessList() throws RemoteException;
+
+    public IIndexOptions getIndexOptions() throws RemoteException;
+
+    public ISOPClass getSOPClass() throws RemoteException;
+
+    public IDirectory getDirectorySettings() throws RemoteException;
+
+    public IUsersManager getUsersManager() throws RemoteException;
+
+    public IActiveSessions getActiveSessions() throws RemoteException;
+    
+    public ITaskList getTaskList() throws RemoteException;
+
+    public IPendingMessages getPendingMessages() throws RemoteException;
+
+    public INetworkInterfaces getNetworkInterface() throws RemoteException;
+
+    public IPluginControllerAdmin getPluginController() throws RemoteException;
+    //public IStatus getStatus() throws RemoteException;
+
+    public String getDefaultFilePath() throws RemoteException;
+    public IRemoteFileSystem getRFS() throws RemoteException;
+
+    //check if there are unsaved Settings
+    public boolean unsavedSettings() throws RemoteException;
+    
+    //Save Settings (print XML)
+    public void saveSettings() throws RemoteException;
+    public void resetSettings() throws RemoteException;
+  
+    public void logout() throws RemoteException;
+
+    public void shutdownServer() throws RemoteException;
+
+    public void KeepAlive() throws RemoteException;
+
+    /**
+     * If the number is equal to the number randomly generated
+     * in Main class, the timetout stops.
+     *
+     * @param number
+     * @return if the number is equal or not
+     * @throws RemoteException
+     */
+    public boolean shtudownTimeout(int number) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/ILogin.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/ILogin.java
new file mode 100755
index 0000000..c403214
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/ILogin.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Login Server interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ILogin extends Remote {
+
+    public IAdmin LoginAdmin(String username, String passwordHash) throws RemoteException;
+    
+    public IUser LoginUser(String username, String passwordHash) throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IUser.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IUser.java
new file mode 100755
index 0000000..ec37518
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/IUser.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.interfaces;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDicomSend;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+
+/**
+ * This interface contains methods that are features to normal users
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IUser extends Remote {
+
+    public String getUsername() throws RemoteException;
+    
+    public boolean changePassword(String oldPassHash, String newPassHash) throws RemoteException;
+
+    public ISearch getSearch() throws RemoteException;
+
+    public IDicomSend getDicomSend() throws RemoteException;
+
+    public void logout() throws RemoteException;
+
+    public void KeepAlive() throws RemoteException;
+
+    public IPluginControllerUser getPluginController() throws RemoteException;
+    /**
+     * If the number is equal to the number randomly generated
+     * in Main class, the timetout stops.
+     *
+     * @param number
+     * @return if the number is equal or not
+     * @throws RemoteException
+     */
+    public boolean shtudownTimeout(int number) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IAccessList.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IAccessList.java
new file mode 100755
index 0000000..204460c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IAccessList.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+
+/**
+ * Access List Settings interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IAccessList extends Remote {
+    public String getAETitle() throws RemoteException;
+    public void setAETitle(String AETitle) throws RemoteException;
+
+    public ArrayList<String> getAccessList() throws RemoteException;
+    public boolean addToAccessList(String AETitle) throws RemoteException;
+    public boolean removeFromAccessList(String AETitle) throws RemoteException;
+
+    public void setPermitAllAETitles(boolean value) throws RemoteException;
+    public boolean getPermitAllAETitles() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IActiveSessions.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IActiveSessions.java
new file mode 100755
index 0000000..651d996
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IActiveSessions.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import pt.ua.dicoogle.server.users.UserON;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IActiveSessions extends Remote {
+
+    public HashMap<Integer, UserON> getUsersTable() throws RemoteException;
+
+    public int getAdminID() throws RemoteException;
+
+    public boolean adminLogoutUser(int ID) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDicomSend.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDicomSend.java
new file mode 100755
index 0000000..30a4cbf
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDicomSend.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IDicomSend extends Remote {
+
+
+    public ArrayList<MoveDestination> getDestinations() throws RemoteException;
+
+    public boolean sendFiles(MoveDestination destination, ArrayList<String> FilePaths) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDirectory.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDirectory.java
new file mode 100755
index 0000000..fa321af
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IDirectory.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Directory Settings interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IDirectory extends Remote {
+
+    /**
+     *
+     * @param path
+     * @return  0 - Ok
+     *          1 - Not a directory
+     *          2 - Can't read
+     *          3 - Can't write
+     * @throws RemoteException
+     */
+    public int setStoragePath(String path) throws RemoteException;
+    public String getStoragePath() throws RemoteException;
+
+    /**
+     *
+     * @param path
+     * @return  0 - Ok
+     *          1 - Not a directory
+     *          2 - Can't read
+     *          3 - Can't write
+     * @throws RemoteException
+     */
+    public int setDicoogleDir(String path) throws RemoteException;
+    public String getDicoogleDir() throws RemoteException;
+
+    /**
+     *
+     * @param effort
+     * @return  true - OK
+     *          false - wrong effort 0 <= effort <= 100
+     * @throws RemoteException
+     */
+    public boolean setIndexerEffort(int effort) throws RemoteException;
+    public int getIndexerEffort() throws RemoteException;
+
+    public void setSaveThumbnails(boolean value) throws RemoteException;
+    public boolean getSaveThumbnails() throws RemoteException;
+
+    public void setThumbnailsMatrix(String ThumbnailsMatrix) throws RemoteException;
+    public String getThumbnailsMatrix() throws RemoteException;
+
+    /**
+     *
+     * @return  0 - OK
+     *          1 - Defined storage path is invalid
+     *          2 - Server running
+     * @throws RemoteException
+     */
+    public int rebuildIndex() throws RemoteException;
+
+    /**
+     *
+     * @return  0 - OK
+     *          1 - Defined storage path is invalid
+     *          2 - Server running
+     * @throws RemoteException
+     */
+    public int rebuildDICOMDir() throws RemoteException;
+
+
+    public boolean isIndexZip() throws RemoteException;
+
+    public void setIndexZip(boolean value) throws RemoteException;
+    
+    
+    public boolean isGZipStorage() throws RemoteException;
+
+    public void setGZipStorage(boolean value) throws RemoteException;
+    
+    public boolean isIndexAnonymous() throws RemoteException;
+
+    public void setIndexAnonymous(boolean value) throws RemoteException;
+    
+    
+    
+    
+    public void setMonitorWatcher(boolean monitorWatcher) throws RemoteException;
+    
+    public boolean isMonitorWatcher() throws RemoteException;
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IIndexOptions.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IIndexOptions.java
new file mode 100755
index 0000000..9c3313d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IIndexOptions.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import pt.ua.dicoogle.sdk.utils.TagValue;
+
+/**
+ * Index Options interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IIndexOptions extends Remote {
+
+    public HashMap<String, ArrayList<TagValue>> getDIMFields() throws RemoteException;
+
+    public boolean isIndexAllModalities() throws RemoteException;
+    public void setIndexAllModalities(boolean value) throws RemoteException;
+    
+    public ArrayList<String> getModalities() throws RemoteException;
+    public boolean addModality(String modality) throws RemoteException;
+    public boolean removeModality(String modality) throws RemoteException;
+    
+    public boolean removeDictionary(String dic) throws RemoteException;
+    public boolean addDictionary(String dic) throws RemoteException;
+
+    public HashMap<String, ArrayList<TagValue>> getManualFields() throws RemoteException;
+    public boolean addManualField(int group, int subGroup, String name) throws RemoteException;
+    public boolean removeManualField(int group, int subGroup) throws RemoteException;
+
+    
+    
+    public void index(String path, boolean resume) throws RemoteException;
+
+    /**
+     * Indexes even if thes files are already indexed
+     *
+     * @param list
+     * @throws RemoteException
+     */
+    public void reIndex(ArrayList<String> list) throws RemoteException;
+
+    public void removeFilesFromIndexer(ArrayList<String> files, boolean deleteFiles) throws RemoteException;
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ILogs.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ILogs.java
new file mode 100755
index 0000000..2ae6528
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ILogs.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import pt.ua.dicoogle.rGUI.interfaces.signals.ILogsSignal;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import pt.ua.dicoogle.DicomLog.LogLine;
+
+/**
+ * Methods avaliable for the Logs Window
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ILogs extends Remote{
+
+    public void RegisterSignalBack(ILogsSignal signalBack) throws RemoteException;
+
+    public ArrayList<LogLine> getPendingDICOMLog() throws RemoteException;
+    public void clearDICOMLog() throws RemoteException;
+
+    public String getServerLog() throws RemoteException;
+    public void clearServerLog() throws RemoteException;
+
+    public String getPendingSessionsLog() throws RemoteException;
+    public void clearSessionsLog() throws RemoteException;
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/INetworkInterfaces.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/INetworkInterfaces.java
new file mode 100755
index 0000000..27f0e49
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/INetworkInterfaces.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public interface INetworkInterfaces extends Remote
+{
+    public ArrayList<String> getNetworkInterfaces() throws RemoteException;
+
+    public void setNetworkInterface(String name) throws RemoteException;
+
+    public String getNetworkInterface() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPendingMessages.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPendingMessages.java
new file mode 100755
index 0000000..29bccbf
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPendingMessages.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import pt.ua.dicoogle.rGUI.interfaces.signals.IPendingMessagesSignal;
+
+/**
+ * The administrator can get the pending messages
+ * using the methods defined in this interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IPendingMessages extends Remote {
+
+    public void RegisterSignalBack(IPendingMessagesSignal signalBack) throws RemoteException;
+
+    public ArrayList<String> getFilesAlreadyIndexed() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerAdmin.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerAdmin.java
new file mode 100755
index 0000000..c8a6b76
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerAdmin.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public interface IPluginControllerAdmin extends Remote
+{
+    public List<String> getPluginNames() throws RemoteException;
+    
+    public void setSettings(HashMap<String, ArrayList> settings) throws RemoteException;
+
+    public HashMap<String, ArrayList> getInitializeParams() throws RemoteException;
+    
+    public void InitiatePlugin(String PluginName) throws RemoteException;
+
+    public void StopPlugin(String PluginName) throws RemoteException;
+
+    public boolean isRunning(String PluginName) throws RemoteException;
+
+    public boolean isLocalPlugin(String PluginName) throws RemoteException;
+
+    public byte[] getJarFile(String PluginName) throws RemoteException;
+
+    public void saveSettings() throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerUser.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerUser.java
new file mode 100755
index 0000000..f1ec967
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IPluginControllerUser.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.List;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Frederico Valente: added graphical part
+ */
+ at Deprecated
+public interface IPluginControllerUser extends Remote
+{
+    public List<String> getPluginNames() throws RemoteException;
+    
+    //public HashMap<String, PluginPanel> getSettingsPanels() throws RemoteException;
+
+    //public void setSettings(HashMap<String, PluginPanel> settings) throws RemoteException;
+
+    //public void InitiatePlugin(String PluginName) throws RemoteException;
+
+    //public void StopPlugin(String PluginName) throws RemoteException;
+
+    public boolean isRunning(String PluginName) throws RemoteException;
+
+    public boolean isLocalPlugin(String PluginName) throws RemoteException;
+    
+        //graphical part for extend the GUI
+    public List<String> getGraphicPluginNames() throws RemoteException;
+    public List<JMenuItem> getRightButtonItems() throws RemoteException;
+    public List<JPanel> getTabPanels() throws RemoteException;
+    public List<JMenuItem> getPluginMenus() throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQRServers.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQRServers.java
new file mode 100755
index 0000000..17f8dbe
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQRServers.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.util.ArrayList;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Methods avaliable for Query/Retrive Servers window
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IQRServers extends Remote {
+
+    /**
+     * Add one Query/Retrieve Server to the list
+     *
+     * @param move
+     * @return
+     */
+    boolean AddEntry(MoveDestination move) throws RemoteException;
+
+    boolean RemoveEntry(MoveDestination move) throws RemoteException;
+
+    ArrayList<MoveDestination> getMoves() throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQueryRetrieve.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQueryRetrieve.java
new file mode 100755
index 0000000..6924c22
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IQueryRetrieve.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+
+/**
+ * Query Retrieve Settings interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IQueryRetrieve extends Remote {
+
+    public int getMaxClientAssoc() throws RemoteException;
+    public void setMaxClientAssoc(int value) throws RemoteException;
+
+    public int getMaxPDULengthReceive() throws RemoteException;
+    public void setMaxPDULengthReceive(int value) throws RemoteException;
+
+    public int getMaxPDULengthSend() throws RemoteException;
+    public void setMaxPDULengthSend(int value) throws RemoteException;
+
+    public int getQRIdleTimeout() throws RemoteException;
+    public void setQRIdleTimeout(int value) throws RemoteException;
+
+    public int getQRAcceptTimeout() throws RemoteException;
+    public void setQRAcceptTimeout(int value) throws RemoteException;
+
+    public int getQRRspDelay() throws RemoteException;
+    public void setQRRspDelay(int value) throws RemoteException;
+
+    public int getQRConnectionTimeout() throws RemoteException;
+    public void setQRConnectionTimeout(int value) throws RemoteException;
+
+    public HashMap<String, String> getFindModalities() throws RemoteException;
+
+    /*
+     * Setters ?
+     * QR port P2P?
+     */
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISOPClass.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISOPClass.java
new file mode 100755
index 0000000..f94431e
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISOPClass.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+
+/**
+ * SOP Class Settings interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ISOPClass extends Remote {
+
+    public ArrayList<SimpleEntry<String, String>> getTransferSyntax() throws RemoteException;
+
+    public ArrayList<String> getSOPClassList() throws RemoteException;
+
+    public String getUID(String sopClass) throws RemoteException;
+
+    public boolean[] getTS(String UID) throws RemoteException;
+    public boolean getAccepted(String UID) throws RemoteException;
+
+    public boolean[] setDefault() throws RemoteException;
+    public boolean[] clearAll() throws RemoteException;
+    public boolean[] setAll() throws RemoteException;
+    public void setTS(String UID, boolean status, int number) throws RemoteException;
+
+    public void setAccepted(String UID, boolean value) throws RemoteException;
+
+    public void saveLocalTS(String UID) throws RemoteException;
+    public void saveAllTS() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISearch.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISearch.java
new file mode 100755
index 0000000..305d064
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ISearch.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.net.URI;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.*;
+import java.util.AbstractMap.SimpleEntry;
+
+import pt.ua.dicoogle.plugins.NetworkMember;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ISearchSignal;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.FileObservable;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ISearch extends Remote {
+
+    // Search
+    public void Search(String query, boolean keywords, HashMap<String, Boolean> range) throws RemoteException;
+    public ListObservableSearch<SearchResult> SearchToExport(String query, boolean keywords, HashMap<String, Boolean> range, ArrayList<String> extraFields, Observer obs) throws RemoteException;
+    public List<SearchResult> SearchIndexedMetaData(SearchResult sresult) throws RemoteException;
+    public void pruneQuery(String id) throws RemoteException;;
+    
+    // Thumnails
+    public SearchResult getThumbnail(URI FileName, String FileHash) throws RemoteException;
+    public void getP2PThumbnail(URI FileName, String FileHash, String addr) throws RemoteException;
+    public ArrayList<SearchResult> getPendingP2PThumnails() throws RemoteException;
+
+    //Search Results
+    public long getSearchTime() throws RemoteException;
+    public List<SearchResult> getSearchResults() throws RemoteException;
+    public List<SearchResult> getP2PSearchResults() throws RemoteException;
+    public List<SearchResult> getExportSearchResults() throws RemoteException;
+
+    public HashMap<String, Integer> getTagList() throws RemoteException;
+
+    public HashMap<Integer, TagValue> getDIMFields() throws RemoteException;
+
+    //Download a file from a remote GUI Server
+    public SimpleEntry<RemoteFile, Integer> downloadFile(SearchResult file) throws RemoteException;
+
+    // Request a File to download from P2P Network
+    public FileObservable RequestP2PFile(SearchResult file) throws RemoteException;
+
+    // get the list of P2P Peers
+    public List<NetworkMember> getPeerList() throws RemoteException;
+    
+    public void RegisterSignalBack(ISearchSignal signalBack) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IServices.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IServices.java
new file mode 100755
index 0000000..a8783f2
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IServices.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.io.IOException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * avaliable methods in Services window
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+
+/*
+ * Considerar a possibilidade de retirar os métodos que indicam o estado de cada
+ * serviço individualmente e adicionar um método que devolve o estado de todos
+ * os serviços (num objecto "EstadoServiços").
+ * 
+ * Apesar da serialização deste objecto, iria diminuir o número de comuniações
+ * entre o servidor e o cliente.
+ *
+ */
+ at Deprecated
+public interface IServices extends Remote {
+
+    boolean stopAllServices() throws RemoteException;
+
+    void startQueryRetrieve() throws RemoteException;
+    void stopQueryRetrieve() throws RemoteException;
+    boolean queryRetrieveIsRunning() throws RemoteException;
+
+    /**
+     *
+     * @return   0 - if everything is fine and the service was started
+     *           1 - if the server's storage path is not defined
+     *           2 - service is already running
+     *
+     * @throws IOException
+     */
+    int startStorage() throws IOException, RemoteException;
+    void stopStorage() throws RemoteException;
+    boolean storageIsRunning() throws RemoteException;
+
+
+    boolean webServerIsRunning() throws RemoteException;
+
+
+    void startWebServices() throws IOException, RemoteException;
+    void stopWebServices() throws IOException, RemoteException;
+    boolean webServicesIsRunning() throws RemoteException;
+    
+    void startWebServer() throws RemoteException;
+    void stopWebServer() throws RemoteException;
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IStartupServ.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IStartupServ.java
new file mode 100755
index 0000000..da506d2
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IStartupServ.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * methods avaliable in Startup Services window
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IStartupServ extends Remote {
+
+    public void setP2P(boolean value) throws RemoteException;
+    public boolean getP2P() throws RemoteException;
+    
+    public void setDICOMStorage(boolean value) throws RemoteException;
+    public boolean getDICOMStorage() throws RemoteException;
+
+    public void setDICOMStoragePort(int value) throws RemoteException;
+    public int getDICOMStoragePort() throws RemoteException;
+
+    public void setDICOMQR(boolean value) throws RemoteException;
+    public boolean getDICOMQR() throws RemoteException;
+
+    public void setDICOMQRPort(int value) throws RemoteException;
+    public int getDICOMQRPort() throws RemoteException;
+
+    public void setWebServer(boolean value) throws RemoteException;
+    public boolean getWebServer() throws RemoteException;
+
+    public void setWebServerPort(int value) throws RemoteException;
+    public int getWebServerPort() throws RemoteException;
+
+    public void setWebServices(boolean value) throws RemoteException;
+    public boolean getWebServices() throws RemoteException;
+
+    public void setWebServicesPort(int value) throws RemoteException;
+    public int getWebServicesPort() throws RemoteException;
+
+    public void setRemoteGUIPort(int value) throws RemoteException;
+    public int getRemoteGUIPort() throws RemoteException;
+
+    public void setRemoteGUIExtIP(String IP) throws RemoteException;
+    public String getRemoteGUIExtIP() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ITaskList.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ITaskList.java
new file mode 100755
index 0000000..44fac15
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/ITaskList.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ITaskListSignal;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public interface ITaskList extends Remote
+{
+    public void RegisterSignalBack(ITaskListSignal signalBack) throws RemoteException;
+    public ArrayList<String> getTaskList() throws RemoteException;
+    public void updatedTasks() throws RemoteException;
+    public boolean isIndexing() throws RemoteException;
+    public int getPercentCompleted() throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IUsersManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IUsersManager.java
new file mode 100755
index 0000000..f085416
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/controllers/IUsersManager.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.controllers;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+
+/**
+ * Users Manager Settings interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IUsersManager extends Remote {
+
+    public boolean getEncryptUsersFile() throws RemoteException;
+    public void setEncryptUsersFile(boolean value) throws RemoteException;
+
+    public ArrayList<String> getUsernames() throws RemoteException;
+    public boolean isAdmin(String username) throws RemoteException;
+
+    public boolean deleteUser(String username) throws RemoteException;
+    public boolean addUser(String username, String passwordHash, boolean admin) throws RemoteException;
+
+    public boolean resetPassword(String username, String passwordHash) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ILogsSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ILogsSignal.java
new file mode 100755
index 0000000..92e8241
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ILogsSignal.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.signals;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Server sends one signal that indicates new Log
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ILogsSignal extends Remote {
+
+    /**
+     *
+     * @param flag
+     *              0 - DICOM Log
+     *              1 - Server Log
+     *              2 - User Sessions Log
+     * @throws RemoteException
+     */
+    public void sendLogSignal(int flag) throws RemoteException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/IPendingMessagesSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/IPendingMessagesSignal.java
new file mode 100755
index 0000000..b31728a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/IPendingMessagesSignal.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.signals;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Pending messages signal interface
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface IPendingMessagesSignal extends Remote {
+
+    /**
+     *
+     * @param flag
+     *              0 - File Already Indexed
+     * @throws RemoteException
+     */
+    public void sendPendingMessagesSignal(int flag) throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ISearchSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ISearchSignal.java
new file mode 100755
index 0000000..bd4e180
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ISearchSignal.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.interfaces.signals;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public interface ISearchSignal extends Remote {
+    /**
+     *
+     * @param flag
+     *              0 - new ArrayList<SearchResult> with the local results
+     *              1 - new ArrayList<SearchResultP2P> with the P2P results
+     *              2 - new SearchTime
+     *              3 - new ArrayList<SearchResultP2P> with P2P Thumbnails requested
+     *              4 - new ArrayList<SearchResult> with the results
+     * @throws RemoteException
+     */
+    public void sendSearchSignal(int flag) throws RemoteException;
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ITaskListSignal.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ITaskListSignal.java
new file mode 100755
index 0000000..9b29312
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/interfaces/signals/ITaskListSignal.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.interfaces.signals;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * TaskList
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public interface ITaskListSignal extends Remote
+{
+    public void sendTaskSignal(int flag) throws RemoteException;
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/package-info.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/package-info.java
new file mode 100644
index 0000000..8cb3e13
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/package-info.java
@@ -0,0 +1,3 @@
+ at Deprecated
+/* @deprecated */
+package pt.ua.dicoogle.rGUI;
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/AdminFeatures.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/AdminFeatures.java
new file mode 100755
index 0000000..4907929
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/AdminFeatures.java
@@ -0,0 +1,545 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.rmi.NoSuchObjectException;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.slf4j.LoggerFactory;
+
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.INetworkInterfaces;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerAdmin;
+
+import pt.ua.dicoogle.server.ControlServices;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.core.XMLSupport;
+import pt.ua.dicoogle.rGUI.MultihomeSslRMIClientSocketFactory;
+
+import pt.ua.dicoogle.rGUI.RFileBrowser.IRemoteFileSystem;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFileSystemServer;
+
+import pt.ua.dicoogle.rGUI.interfaces.IAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IAccessList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDirectory;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IIndexOptions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ILogs;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQRServers;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQueryRetrieve;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISOPClass;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IServices;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IStartupServ;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ITaskList;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IUsersManager;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IActiveSessions;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPendingMessages;
+
+import pt.ua.dicoogle.rGUI.server.controllers.AccessList;
+import pt.ua.dicoogle.rGUI.server.controllers.DirectorySettings;
+import pt.ua.dicoogle.rGUI.server.controllers.IndexOptions;
+import pt.ua.dicoogle.rGUI.server.controllers.Logs;
+import pt.ua.dicoogle.rGUI.server.controllers.PendingMessages;
+import pt.ua.dicoogle.rGUI.server.controllers.QRServers;
+import pt.ua.dicoogle.rGUI.server.controllers.QueryRetrieve;
+import pt.ua.dicoogle.rGUI.server.controllers.SOPClass;
+import pt.ua.dicoogle.rGUI.server.controllers.StartupServices;
+import pt.ua.dicoogle.rGUI.server.controllers.TaskList;
+import pt.ua.dicoogle.rGUI.server.controllers.UsersManager;
+import pt.ua.dicoogle.rGUI.server.controllers.NetworkInterfaces;
+import pt.ua.dicoogle.rGUI.server.controllers.PluginController4Admin;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UserSessions;
+
+/**
+ * This class serves to provide access to administration features
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class AdminFeatures implements IAdmin {
+
+    private static AdminFeatures instance = null;
+
+    private XMLSupport xmlSupport;
+
+    private Timer timer;
+    private static int timeoutTime = 15000; //15 seconds
+    private TimerTask task;
+    private boolean timeoutCanceled = false;
+
+    private User user;
+
+    private int port;
+
+    private IUser userStub = null;     //reference to stub of UserFeatures
+
+    public static synchronized AdminFeatures getInstance() {
+        if (instance == null) {
+            instance = new AdminFeatures();
+        }
+
+        return instance;
+    }
+
+    private AdminFeatures() {
+        xmlSupport = new XMLSupport();
+
+        port = ServerSettings.getInstance().getRemoteGUIPort();
+    }
+
+    @Override
+    public IServices getServices() throws RemoteException {
+        try{
+            return (IServices) UnicastRemoteObject.toStub(ControlServices.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IServices) UnicastRemoteObject.exportObject(ControlServices.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IQRServers getQRServers() throws RemoteException {
+        try{
+            return (IQRServers) UnicastRemoteObject.toStub(QRServers.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IQRServers) UnicastRemoteObject.exportObject(QRServers.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public ILogs getLogs() throws RemoteException {
+        try{
+            return (ILogs) UnicastRemoteObject.toStub(Logs.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (ILogs) UnicastRemoteObject.exportObject(Logs.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IStartupServ getStartupServ() throws RemoteException {
+        try{
+            return (IStartupServ) UnicastRemoteObject.toStub(StartupServices.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IStartupServ) UnicastRemoteObject.exportObject(StartupServices.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IQueryRetrieve getQueryRetrive() throws RemoteException {
+        try{
+            return (IQueryRetrieve) UnicastRemoteObject.toStub(QueryRetrieve.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IQueryRetrieve) UnicastRemoteObject.exportObject(QueryRetrieve.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IAccessList getAccessList() throws RemoteException {
+        try{
+            return (IAccessList) UnicastRemoteObject.toStub(AccessList.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IAccessList) UnicastRemoteObject.exportObject(AccessList.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IIndexOptions getIndexOptions() throws RemoteException {
+        try{
+            return (IIndexOptions) UnicastRemoteObject.toStub(IndexOptions.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IIndexOptions) UnicastRemoteObject.exportObject(IndexOptions.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public ISOPClass getSOPClass() throws RemoteException {
+        try{
+            return (ISOPClass) UnicastRemoteObject.toStub(SOPClass.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (ISOPClass) UnicastRemoteObject.exportObject(SOPClass.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IDirectory getDirectorySettings() throws RemoteException {
+        try{
+            return (IDirectory) UnicastRemoteObject.toStub(DirectorySettings.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IDirectory) UnicastRemoteObject.exportObject(DirectorySettings.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IUsersManager getUsersManager() throws RemoteException {
+        try{
+            return (IUsersManager) UnicastRemoteObject.toStub(UsersManager.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IUsersManager) UnicastRemoteObject.exportObject(UsersManager.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+
+    @Override
+    public IActiveSessions getActiveSessions() throws RemoteException {
+        try{
+            return (IActiveSessions) UnicastRemoteObject.toStub(UserSessions.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IActiveSessions) UnicastRemoteObject.exportObject(UserSessions.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+
+    /**
+     * @return the taskList
+     */
+    @Override
+    public ITaskList getTaskList() throws RemoteException{
+        try{
+            return (ITaskList) UnicastRemoteObject.toStub(TaskList.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (ITaskList) UnicastRemoteObject.exportObject(TaskList.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    /**
+     * @return the pending messages controler remote reference
+     */
+    @Override
+    public IPendingMessages getPendingMessages() throws RemoteException{
+        try{
+            return (IPendingMessages) UnicastRemoteObject.toStub(PendingMessages.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IPendingMessages) UnicastRemoteObject.exportObject(PendingMessages.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+    @Override
+    public IRemoteFileSystem getRFS() throws RemoteException {
+        try{
+            return (IRemoteFileSystem) UnicastRemoteObject.toStub(RemoteFileSystemServer.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IRemoteFileSystem) UnicastRemoteObject.exportObject(RemoteFileSystemServer.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+    
+    @Override
+    public IPluginControllerAdmin getPluginController() throws RemoteException
+    {
+        try{
+            return (IPluginControllerAdmin) UnicastRemoteObject.toStub(PluginController4Admin.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (IPluginControllerAdmin) UnicastRemoteObject.exportObject(PluginController4Admin.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+
+    }
+
+    
+    @Override
+    public INetworkInterfaces getNetworkInterface() throws RemoteException {
+        try{
+            return (INetworkInterfaces) UnicastRemoteObject.toStub(NetworkInterfaces.getInstance());
+        }catch(NoSuchObjectException ex){
+            return (INetworkInterfaces) UnicastRemoteObject.exportObject(NetworkInterfaces.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+    }
+
+
+    /**
+     * Unexport all the remote objects related to the administration
+     * 
+     * @throws RemoteException
+     */
+    @Override
+    public void logout() throws RemoteException {
+        timer.cancel();
+
+        // reset the signalBack object reference
+        TaskList.getInstance().resetSignalBack();
+        Logs.getInstance().resetSignalBack();
+        PendingMessages.getInstance().resetSignalBack();
+
+        try {
+            UnicastRemoteObject.unexportObject(ControlServices.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(QRServers.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(Logs.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(StartupServices.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(QueryRetrieve.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(AccessList.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(IndexOptions.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(SOPClass.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(DirectorySettings.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(UsersManager.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+        
+        try {
+            UnicastRemoteObject.unexportObject(UserSessions.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(RemoteFileSystemServer.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+        
+        
+        try {
+            UnicastRemoteObject.unexportObject(TaskList.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+        
+        try {
+            UnicastRemoteObject.unexportObject(PendingMessages.getInstance(), true);
+        } catch (NoSuchObjectException ex) {}; 
+
+        try {
+            UnicastRemoteObject.unexportObject(NetworkInterfaces.getInstance(), true);
+        } catch (NoSuchObjectException ex) {};  
+        
+        try {
+            UnicastRemoteObject.unexportObject(PluginController4Admin.getInstance(), true);
+        } catch (NoSuchObjectException ex) {};  
+        
+        
+        resetSettings();
+
+        this.user = null;
+        userStub = null;
+        timeoutCanceled = false;
+
+        //removes the administrator session
+        UserSessions.getInstance().adminLogout();
+        
+        // unexport this object
+        try {
+            UnicastRemoteObject.unexportObject(this, true);
+        } catch (NoSuchObjectException ex) {};    
+    }
+
+    /**
+     * Save ServerSettings
+     *  This funcion has to call the other "save" functions of the administration object
+     *  Finnaly it has to print XML with new ServerSettings
+     *
+     * @throws RemoteException
+     */
+    @Override
+    public void saveSettings() throws RemoteException {
+
+        StartupServices.getInstance().saveSettings();
+        QueryRetrieve.getInstance().saveSettings();
+        AccessList.getInstance().saveSettings();
+        IndexOptions.getInstance().saveSettings();
+        DirectorySettings.getInstance().saveSettings();
+        QRServers.getInstance().saveSettings();
+        UsersManager.getInstance().saveSettings();
+
+        xmlSupport.printXML();
+        /**
+         * ATTENTION: this settings are stored appart from the others in the
+         * filepath: /plugins/settings/PLUGIN_NAME.settings
+         * They are also stored in binary format instead of XML.
+         */
+        PluginController4Admin.getInstance().saveSettings();
+        
+        //DebugManager.getInstance().debug("Settings saved!");
+    }
+
+    /**
+     * check if there ara unsaved Settings
+     *
+     * @return true if there are unsaved settings
+     * @throws RemoteException
+     */
+    @Override
+    public boolean unsavedSettings() throws RemoteException {
+        return StartupServices.getInstance().unsavedSettings() || QueryRetrieve.getInstance().unsavedSettings()
+                || AccessList.getInstance().unsavedSettings() || IndexOptions.getInstance().unsavedSettings()
+                || DirectorySettings.getInstance().unsavedSettings() || QRServers.getInstance().unsavedSettings()
+                || UsersManager.getInstance().unsavedSettings();
+    }
+
+    
+
+    @Override
+    public String getDefaultFilePath() throws RemoteException {
+        return ServerSettings.getInstance().getPath();
+    }
+
+    
+    /**
+     * Restore settings, discard all unsaved settings
+     * 
+     * @throws RemoteException
+     */
+    @Override
+    public void resetSettings() throws RemoteException {
+        if (StartupServices.getInstance().unsavedSettings()) {
+            StartupServices.getInstance().loadSettings();
+        }
+
+        if (QueryRetrieve.getInstance().unsavedSettings()) {
+            QueryRetrieve.getInstance().loadSettings();
+        }
+
+        if (AccessList.getInstance().unsavedSettings()) {
+            AccessList.getInstance().loadSettings();
+        }
+
+        if (IndexOptions.getInstance().unsavedSettings()) {
+            IndexOptions.getInstance().loadSettings();
+        }
+
+        if (DirectorySettings.getInstance().unsavedSettings()) {
+            DirectorySettings.getInstance().loadSettings();
+        }
+
+        if (QRServers.getInstance().unsavedSettings()) {
+            QRServers.getInstance().loadSettings();
+        }
+
+        if (UsersManager.getInstance().unsavedSettings()) {
+            UsersManager.getInstance().loadSettings();
+        }
+    }
+
+    @Override
+    public String getUsername() throws RemoteException {
+        if (user != null) {
+            return user.getUsername();
+        }
+
+        return null;
+    }
+
+    @Override
+    public void KeepAlive() throws RemoteException {
+        if(!timeoutCanceled){
+            task.cancel();
+            timer.purge();
+
+            task = new TimeOut();
+            timer.schedule(task, timeoutTime, timeoutTime);
+        }
+    }
+
+    @Override
+    public IUser getUser() throws RemoteException {
+        if (userStub == null) {
+            UserFeatures userF = new UserFeatures(user);
+            UserSessions.getInstance().setAdminUserFeatures(userF); //saves the UserFeatures of this admin
+
+            userStub = (IUser) UnicastRemoteObject.exportObject(userF, 0, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+
+        return userStub;
+    }
+
+    
+    public void setUser(User user) {
+        this.user = user;
+        
+        timer = new Timer();
+        task = new TimeOut();
+
+        timer.schedule(task, timeoutTime, timeoutTime); 
+    }
+
+    @Override
+    public void shutdownServer() throws RemoteException {
+        //shutdown the services
+        ControlServices.getInstance().stopAllServices();
+
+        //logout the admin
+        this.logout();
+
+        //logout the users
+        UserSessions.getInstance().adminLogoutAllUsers();
+
+        //DebugManager.getInstance().debug("The Server is Shutting Down!");
+        
+        //close Dicoogle Server
+        System.exit(0);
+    }
+
+    
+    /**
+     * If the number is equal to the number randomly generated
+     * in Main class, the timetout stops.
+     *
+     * @param number
+     * @return if the number is equal or not
+     * @throws RemoteException
+     */
+    @Override
+    public boolean shtudownTimeout(int number) throws RemoteException {
+        if(number == Main.randomInteger){
+            timeoutCanceled = true;
+            task.cancel();
+            timer.purge();
+
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * This class extends TimerTask
+     * and when the run method is called the admin logout
+     */
+    private class TimeOut extends TimerTask {
+
+        @Override
+        public void run() {
+            try {
+                logout();
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(UserFeatures.class).error(ex.getMessage(), ex);
+            }
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/DicoogleScan.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/DicoogleScan.java
new file mode 100755
index 0000000..45c5c25
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/DicoogleScan.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.dcm4che2.io.DicomInputStream;
+
+
+import pt.ua.dicoogle.plugins.PluginController;
+
+/**
+ *
+ * @author carloscosta
+ */
+ at Deprecated
+public class DicoogleScan {
+    private File path = null;
+
+    public DicoogleScan(File path){
+        this.path = path;
+    }
+
+    public DicoogleScan(String path){
+        this(new File(path));
+    }
+    public void scan(boolean resume){
+        scan(path, resume);
+    }
+
+    private void scan(File path, boolean resume){
+        if (path == null)
+                return;
+
+            
+        
+            //long time = System.nanoTime();
+
+            // O Método FileIndexer.index já a indexação recursiva de files DICOM
+            
+            System.out.println("Calling Index");
+            PluginController.getInstance().index(path.toURI());
+            
+
+            //core.indexQueue(path.getAbsolutePath(), resume);
+
+            //System.out.println("\n***Directory Index Time (miliseg)***"
+            //                 + "\nStart Time: " + time + "\nEnd Time:" + System.nanoTime()
+            //                 + "\nDelta Time: " + ((System.nanoTime() - time)/1000000L));
+
+    }
+
+    public static boolean isDicom(File file) throws IOException
+    {
+        boolean result = false;
+        DicomInputStream dis = new DicomInputStream(file);
+        if (dis.getTransferSyntax() != null)
+            result = true;
+        return result;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/GUIServer.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/GUIServer.java
new file mode 100755
index 0000000..abd709b
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/GUIServer.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.ExportException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.rmi.server.UnicastRemoteObject;
+
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+import javax.swing.JOptionPane;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.MultihomeSslRMIClientSocketFactory;
+
+import pt.ua.dicoogle.rGUI.interfaces.ILogin;
+import pt.ua.dicoogle.utils.KeysManager;
+
+/**
+ * This class creates the GUI Server over RMI
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class GUIServer {
+
+    private int port;
+    private Registry reg;
+
+    /**
+     * Start the RMI GUI Server.
+     * Creates an RMI Registry on localhost
+     *
+     * @param port - where the RMI Registry will be bound
+     */
+    public GUIServer(){
+        
+        setProperties();
+
+        while(true){
+            this.port = ServerSettings.getInstance().getRemoteGUIPort();
+
+
+            try {
+                //creates a Registrey for associating names with objects
+                reg = LocateRegistry.createRegistry(this.port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+
+                //reg = LocateRegistry.createRegistry(this.port);
+                // creates the remote object
+                ILogin stub = (ILogin) UnicastRemoteObject.exportObject(Login.getInstance(), this.port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+                //ILogin stub = (ILogin) UnicastRemoteObject.exportObject(Login.getInstance(), 0);
+
+                //Associates the Remote Object to its name in the Registry
+                reg.rebind("login", stub);
+
+                //DebugManager.getInstance().debug("GUI Server is running on port " + this.port +".");
+
+                break;
+            } catch(ExportException ex){
+                /*
+                 JOptionPane.showMessageDialog(null, "Another server process is already running on port " + this.port,
+                        "Startup Error", JOptionPane.ERROR_MESSAGE);
+                 */
+
+                String sPort = JOptionPane.showInputDialog(null, "Another server process is already running on port " + this.port
+                        +"!\nDo you want to try another port?", "Startup Error", JOptionPane.ERROR_MESSAGE);
+
+                try{
+                    int pt = Integer.valueOf(sPort);
+                    ServerSettings.getInstance().setRemoteGUIPort(pt);
+                }
+                catch(Exception e){
+                    JOptionPane.showMessageDialog(null, "Port Invalid!",
+                        "Startup Error", JOptionPane.ERROR_MESSAGE);
+                    System.exit(-4);
+                }
+                
+
+            } catch (Exception ex) {
+                //DebugManager.getInstance().debug("Error associating the remote object to the NameRegistry!");
+
+                LoggerFactory.getLogger(GUIServer.class).error(ex.getMessage(), ex);
+
+                break;
+            }
+        }
+    }
+
+    /**
+     * Set the properties that are accurate to the RMI Server
+     */
+    private void setProperties(){
+        String keyStorePath = KeysManager.getServerKeyPath();
+
+        /**
+         * Put the external IP address into the java.rmi.server.hostname property
+         */
+        String externIP = ServerSettings.getInstance().getRGUIExternalIP();
+        if(externIP != null && !externIP.equals(""))
+        {
+            String hostname = System.getProperty("java.rmi.server.hostname");
+            System.setProperty("java.rmi.server.hostname", hostname + "!" + externIP);
+        }
+
+        //define the System properties to use a SSLKeystore
+        System.setProperty("javax.net.ssl.keyStore", keyStorePath);
+        System.setProperty("javax.net.ssl.keyStorePassword", "dicooglepacs");
+
+        if (Main.isFixedClient()) {
+            String TrustStorePath = KeysManager.getClientKeyPath();
+
+            //define the System property to use a SSL TrustStore
+            System.setProperty("javax.net.ssl.trustStore", TrustStorePath);
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/Login.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/Login.java
new file mode 100755
index 0000000..e55eccd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/Login.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.rmi.RemoteException;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UnicastRemoteObject;
+import java.rmi.server.RemoteServer;
+
+import pt.ua.dicoogle.rGUI.interfaces.ILogin;
+
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+import pt.ua.dicoogle.rGUI.MultihomeSslRMIClientSocketFactory;
+import pt.ua.dicoogle.rGUI.interfaces.IAdmin;
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UserSessions;
+import pt.ua.dicoogle.server.users.UsersStruct;
+import pt.ua.dicoogle.server.users.UsersXML;
+
+/**
+ * Login of users and administrator
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class Login implements ILogin {
+
+    private static Login instance = null;
+
+    private UsersStruct users;
+    private UserSessions sessions;
+
+    public static synchronized Login getInstance() {
+        if (instance == null) {
+            instance = new Login();
+        }
+
+        return instance;
+    }
+
+    private Login() {
+        new UsersXML().getXML(); // read XML with users and set the UsersStruct object (singleton)
+
+        sessions = UserSessions.getInstance();
+        users = UsersStruct.getInstance();
+    }
+
+    /*
+     * Public remote interface methods
+     */
+    @Override
+    public IAdmin LoginAdmin(String username, String passwordHash) throws RemoteException {
+        User user = users.getUser(username);
+        String adminHost = "";
+        
+        if (user != null && user.verifyPassword(passwordHash) && user.isAdmin()) {            
+            
+            try {
+                adminHost = RemoteServer.getClientHost();
+            } catch (ServerNotActiveException ex){ }
+
+            if (sessions.adminLogin(user, adminHost) != -1) {
+                AdminFeatures admin = AdminFeatures.getInstance();
+                admin.setUser(user);
+                return (IAdmin) UnicastRemoteObject.exportObject(admin, 0, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+            }
+            else{
+                return null;
+            }
+        }
+
+        sessions.loginFailed(username, adminHost, true);
+        return null;
+    }
+
+    @Override
+    public IUser LoginUser(String username, String passwordHash) throws RemoteException {
+        User user = users.getUser(username);
+        String userHost = "";
+
+        try {
+                userHost = RemoteServer.getClientHost();
+            } catch (ServerNotActiveException ex){ }
+
+        if (user != null && user.verifyPassword(passwordHash)){
+
+            IUser userStub = null;
+
+            UserFeatures userF = new UserFeatures(user);
+            sessions.userLogin(user, userHost, userF);
+
+            userStub = (IUser) UnicastRemoteObject.exportObject(userF, 0, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+
+            return userStub;
+        }
+
+        sessions.loginFailed(username, userHost, false);
+
+        return null;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/SearchHelper.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/SearchHelper.java
new file mode 100755
index 0000000..1fa1887
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/SearchHelper.java
@@ -0,0 +1,218 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.server.controllers.Search;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class SearchHelper implements Observer
+{
+
+    private ListObservableSearch<SearchResult> SearchResList = null;
+    private boolean export = false; // indicates whether the search is to export or do not
+    private long time;
+    private Search searchControler;
+
+    public SearchHelper(Search search)
+    {
+        this.searchControler = search;
+
+
+    }
+
+    public void setList(ListObservableSearch<SearchResult> SearchResList)
+    {
+        this.SearchResList = SearchResList;
+    }
+    
+    
+    public ListObservableSearch<SearchResult> search(String query, ArrayList<String> extrafields,
+            HashMap<String, Boolean> plugins, boolean export, Observer obs)
+    {
+    
+        this.export = export;
+        this.time = System.nanoTime();
+
+    ArrayList<String> plugins2 = new ArrayList<String>();    
+        for (String pi : plugins.keySet())
+        {
+            Boolean value = plugins.get(pi);
+            if (value)
+            {
+                    plugins2.add(pi);
+
+            }
+            
+        }
+        
+        
+        Thread seachThread = new SearchLocal(query, extrafields, plugins2, obs);
+        seachThread.start();
+        return SearchResList;
+        
+        
+    }
+    
+    
+    public void search(String query, ArrayList<String> extrafields,
+            HashMap<String, Boolean> plugins, boolean export)
+    {
+        search(query, extrafields, plugins, export, this);
+    
+    }
+
+    public SearchResult searchThumbnail(URI FileName, String FileHash)
+    {
+        ArrayList<SearchResult> queryResultListLocal;
+
+        ArrayList<String> extrafields = new ArrayList<String>();
+        extrafields.add("Thumbnail");
+
+        String query = "FileName:" + FileName + " AND FileHash:" + FileHash;
+        // TODO: Implement it.
+        return null;
+    }
+
+    public void searchP2PThumbnail(URI FileName, String FileHash, String addr)
+    {
+
+        ArrayList<String> extrafields = new ArrayList<String>();
+        extrafields.add("Thumbnail");
+
+        String query = "FileName:" + FileName + " AND FileHash:" + FileHash;
+        // TODO: Implement it.
+    }
+
+    @Override
+    public void update(Observable o, Object arg)
+    {
+        
+        ArrayList tmp = ((ListObservableSearch) o).getArray();
+        Boolean finished = ((ListObservableSearch) o).isFinish();
+        System.out.println("SearchHelper...recebeu os resultados: " + tmp.size());
+        ArrayList<SearchResult> resultsList;
+        
+        if (tmp.isEmpty())
+        {
+            return;
+                  
+        } else
+        {
+            
+            ((ListObservableSearch) o).resetArray();
+            
+            if (SearchResult.class.isInstance(tmp.get(0)))
+            {
+                
+                if (finished)
+                {
+                    searchControler.queryFinished();
+                }
+                
+                    resultsList = tmp;
+
+                    if (resultsList.size() == 1 && resultsList.get(0).getExtraData().size() == 0)
+                    {
+                       return;
+                    }
+
+                    //if the result is just the requested Thumbnail
+                    if (resultsList.size() == 1 && resultsList.get(0).getExtraData().size() == 1
+                            && resultsList.get(0).getExtraData().get("Thumbnail") != null)
+                    {
+                        searchControler.setP2PThumbnails(resultsList);
+                        
+                    } else
+                    {
+                        ((ListObservableSearch) o).resetArray();
+                        long timeEnd = System.nanoTime();
+
+                        if (!export)
+                        {
+                            searchControler.setSearchTime(((int) ((timeEnd - time) / 1000000L)));
+                            searchControler.setP2PSearchResult(resultsList);
+                        } else
+                        {
+                            searchControler.setExportSearchResult(resultsList);
+                        }
+                        
+                        PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_BLOCK_SIGNAL, null, null));
+                    }
+           
+            }
+            
+            
+            // Memory monitoring 
+             long freeMemory = Runtime.getRuntime().freeMemory() / 1024 / 1024;
+             long totalMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
+             long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
+             
+             double percentage = freeMemory / totalMemory;
+             
+             if (percentage>0.8)
+             {
+                 // Prune query!!! 
+                 PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_QUERY_PRUNE, null, null));
+             }
+        }
+        
+    }
+
+    /**
+     * Private class that implements one Thread to search in IndexEngine
+     */
+    private class SearchLocal extends Thread
+    {
+
+        private String query;
+        private ArrayList<String> extrafields;
+        private ArrayList<String> pluginsLocals;
+        private Observer searchHelper;
+
+        public SearchLocal(String query, ArrayList<String> extrafields, ArrayList<String> pluginsLocals , Observer searchHelper)
+        {
+            this.query = query;
+            this.extrafields = extrafields;
+            this.pluginsLocals = pluginsLocals;
+            this.searchHelper = searchHelper;
+        }
+
+        @Override
+        public void run()
+        {
+            //TODO: DELETED
+        	//SearchResList = PluginController.getInstance().search(pluginsLocals, query, extrafields, searchHelper);
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/UserFeatures.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/UserFeatures.java
new file mode 100755
index 0000000..738bb33
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/UserFeatures.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server;
+
+import java.rmi.NoSuchObjectException;
+import java.rmi.NoSuchObjectException;
+import pt.ua.dicoogle.server.users.UserSessions;
+import java.util.Timer;
+import java.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+import pt.ua.dicoogle.Main;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.MultihomeSslRMIClientSocketFactory;
+
+import pt.ua.dicoogle.rGUI.interfaces.IUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDicomSend;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerUser;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+import pt.ua.dicoogle.rGUI.server.controllers.DicomSend;
+import pt.ua.dicoogle.rGUI.server.controllers.PluginController4user;
+import pt.ua.dicoogle.rGUI.server.controllers.Search;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UsersXML;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class UserFeatures implements IUser {
+    private UserSessions userSessions;
+    private User user;
+    private int port;
+
+    private Timer timer;
+    private static int timeoutTime = 10000; //10 seconds
+    private TimerTask task;
+    private boolean timeoutCanceled = false;
+
+    /*
+     * These are the controlers that have been exported to RMI
+     */
+    private ISearch search = null, searchStub = null;
+    private IPluginControllerUser pcontroller = null;
+    private static IDicomSend dicomSendStub = null;
+
+
+    public UserFeatures(User user) {
+        userSessions = UserSessions.getInstance();
+
+        this.user = user;
+
+        timer = new Timer();
+        task = new TimeOut();
+
+        timer.schedule(task, timeoutTime, timeoutTime);
+
+        port = ServerSettings.getInstance().getRemoteGUIPort();
+    }
+
+    @Override
+    public void logout() throws RemoteException {
+        task.cancel();
+
+        if(search != null){
+            UnicastRemoteObject.unexportObject(search, true);
+            search = null;
+        }
+        
+        
+        // unexport this object^M
+        try {
+            UnicastRemoteObject.unexportObject(this, true);
+        } catch (NoSuchObjectException ex) {}; 
+        userSessions.userLogout(this);
+    }
+
+    
+    @Override
+    public boolean changePassword(String oldPassHash, String newPassHash) throws RemoteException {
+        boolean result = user.changePassword(oldPassHash, newPassHash);
+
+        // save the xml with new user informations
+        if(result){
+            UsersXML xml = new UsersXML();
+            xml.printXML();
+        }
+        return result;
+    }
+
+    @Override
+    public String getUsername() throws RemoteException {
+        if(user != null)
+            return user.getUsername();
+        
+        return "";
+    }
+
+    @Override
+    public ISearch getSearch() throws RemoteException {
+        if(search == null)
+        {
+            search = new Search();
+
+            searchStub = (ISearch) UnicastRemoteObject.exportObject(search, port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+
+        return searchStub;
+    }
+
+
+    @Override
+    public IDicomSend getDicomSend() throws RemoteException {
+        if(dicomSendStub == null)
+            dicomSendStub = (IDicomSend) UnicastRemoteObject.exportObject(DicomSend.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+
+        return dicomSendStub;
+    }
+
+
+    /**
+     * Cancel the task and reschedule the task
+     * @throws RemoteException
+     */
+    @Override
+    public void KeepAlive() throws RemoteException {
+        if(!timeoutCanceled){
+            task.cancel();
+            timer.purge();
+
+            task = new TimeOut();
+            timer.schedule(task, timeoutTime, timeoutTime);
+        }
+    }
+
+    /**
+     * If the number is equal to the number randomly generated
+     * in Main class, the timetout stops.
+     *
+     * @param number
+     * @return if the number is equal or not
+     * @throws RemoteException
+     */
+    @Override
+    public boolean shtudownTimeout(int number) throws RemoteException {
+        if(number == Main.randomInteger){
+            timeoutCanceled = true;
+            task.cancel();
+            timer.purge();
+
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public IPluginControllerUser getPluginController() throws RemoteException
+    {
+        if(pcontroller == null)
+        {
+            pcontroller = (IPluginControllerUser) UnicastRemoteObject.exportObject(PluginController4user.getInstance(), port, new MultihomeSslRMIClientSocketFactory(), new SslRMIServerSocketFactory());
+        }
+        return pcontroller;
+    }
+
+    
+    /**
+     * This class extends TimerTask
+     * and when the run method is called the user logout
+     */
+    private class TimeOut extends TimerTask{
+
+        @Override
+        public void run() {
+            try {
+                logout();
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(UserFeatures.class).error(ex.getMessage(), ex);
+            }
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/AccessList.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/AccessList.java
new file mode 100755
index 0000000..2dacf10
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/AccessList.java
@@ -0,0 +1,169 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IAccessList;
+
+/**
+ * Controller of Access List to DICOM services
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class AccessList implements IAccessList {
+    private ServerSettings settings;
+
+    private String AETitle;
+    private ArrayList<String> list;
+    private boolean permitAllAETitles;
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static AccessList instance = null;
+
+    public static synchronized AccessList getInstance()
+    {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new AccessList();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private AccessList(){
+        settings = ServerSettings.getInstance();
+
+        loadSettings();
+    }
+
+    /**
+     * Load settings from ServerSettings
+     */
+    public void loadSettings(){
+        AETitle = settings.getAE();
+        permitAllAETitles = settings.getPermitAllAETitles();
+
+        list = new ArrayList<String>();
+
+        String[] CAET = settings.getCAET();
+        
+        if(CAET != null)
+            for(String AET : CAET)
+                list.add(AET);
+    }
+
+    /**
+     * Save the settings related to Access List
+     *
+     * not write the settings in XML
+     */
+    public void saveSettings(){
+        settings.setAE(AETitle);
+        settings.setPermitAllAETitles(permitAllAETitles);
+
+        String[] CAET = new String[list.size()];
+        CAET = list.toArray(CAET);
+
+        settings.setCAET(CAET);
+    }
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != ServerSettings)
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+        if(!AETitle.equals(settings.getAE()) || settings.getPermitAllAETitles() != permitAllAETitles)
+            return true;
+        else{
+            ArrayList<String> tmp = new ArrayList<String>();
+
+            String[] CAET = settings.getCAET();
+
+            if(CAET != null)
+                for(String AET : CAET)
+                    tmp.add(AET);
+            else if(list.size() != 0)
+                return true;
+
+            if (!tmp.equals(list))
+                return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String getAETitle() throws RemoteException {
+        return AETitle;
+    }
+
+    @Override
+    public void setAETitle(String AETitle) throws RemoteException {
+        if(AETitle == null)
+            this.AETitle = " ";
+        else
+            this.AETitle = AETitle;
+    }
+
+    @Override
+    public ArrayList<String> getAccessList() throws RemoteException {
+
+        list.trimToSize(); //trim size of ArrayList
+
+        return list;
+    }
+
+    @Override
+    public boolean addToAccessList(String AETitle) throws RemoteException {
+        if(!list.contains(AETitle))
+            return list.add(AETitle);
+        else
+            return false;
+    }
+
+    @Override
+    public boolean removeFromAccessList(String AETitle) throws RemoteException {
+           
+        return list.remove(AETitle);
+    }
+
+    @Override
+    public void setPermitAllAETitles(boolean value) throws RemoteException {
+        permitAllAETitles = value;
+    }
+
+    @Override
+    public boolean getPermitAllAETitles() throws RemoteException {
+        return permitAllAETitles;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DicomSend.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DicomSend.java
new file mode 100755
index 0000000..9c98e29
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DicomSend.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDicomSend;
+import pt.ua.dicoogle.server.queryretrieve.CallDCMSend;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class DicomSend implements IDicomSend {
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static DicomSend instance = null;
+
+    public static synchronized DicomSend getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new DicomSend();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(DicomSend.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private DicomSend() {
+    }
+
+    @Override
+    public ArrayList<MoveDestination> getDestinations() throws RemoteException {
+        return ServerSettings.getInstance().getMoves();
+    }
+
+    @Override
+    public boolean sendFiles(MoveDestination destination, ArrayList<String> FilePaths) throws RemoteException {
+        if(destination == null || FilePaths == null || FilePaths.isEmpty())
+            return false;
+
+        /**
+         * Convert all images to an array with File list
+         */
+        ArrayList<File> fileList = new ArrayList<File>();
+
+        Iterator<String> it  = FilePaths.iterator();
+        while (it.hasNext()) 
+            fileList.add(new File(it.next()));
+        
+
+         //DebugManager.getInstance().debug("Sending files to Destination");
+         
+        /**
+         * Call DICOM Storage SCU for each image
+         */
+        //DebugManager.getInstance().debug("AETITLE to DICOM STORAGE SCU: "
+          //      + destination.getAETitle());
+
+        try {
+            CallDCMSend s = new CallDCMSend(fileList, destination.getPort(), destination.getIpAddrs(), destination.getAETitle(), null);
+        } catch (Exception ex) {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DirectorySettings.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DirectorySettings.java
new file mode 100755
index 0000000..a3dc545
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/DirectorySettings.java
@@ -0,0 +1,325 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+//import com.sun.tools.javac.util.DefaultFileManager.ZipArchive;
+import pt.ua.dicoogle.server.ControlServices;
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IDirectory;
+import pt.ua.dicoogle.server.DicomDirCreator;
+
+/**
+ * Controller of Directory Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class DirectorySettings implements IDirectory {
+
+    private static final Logger logger = LoggerFactory.getLogger(DirectorySettings.class);
+    
+    private String storagePath;
+    private String dicoogleDir;
+    private int effort;
+    private boolean saveTumbnails;
+    private String thumbnailsMatrix;
+    private boolean indezZip;
+    private boolean gzipStorage;
+    private boolean indexAnonymous;
+    private boolean monitorWatcher;
+    
+
+    private ServerSettings settings;
+    
+    private static DirectorySettings instance ;
+
+    public static synchronized DirectorySettings getInstance()
+    {
+
+        if (instance == null) 
+            instance = new DirectorySettings();
+
+        return instance;
+    }
+
+    private DirectorySettings()
+    {
+        settings = ServerSettings.getInstance();
+
+        loadSettings();
+    }
+
+    /**
+     * Load settings from ServerSettings
+     */
+    public void loadSettings(){
+        storagePath = settings.getPath();
+        dicoogleDir = settings.getDicoogleDir();
+        effort = settings.getIndexerEffort();
+        saveTumbnails = settings.getSaveThumbnails();
+        thumbnailsMatrix = settings.getThumbnailsMatrix();
+        indezZip = settings.isIndexZIPFiles();
+        gzipStorage = settings.isGzipStorage();
+        monitorWatcher = settings.isMonitorWatcher();
+        this.indexAnonymous = settings.isIndexAnonymous();
+    }
+
+    /**
+     * Save settings to ServerSettings
+     */
+    public void saveSettings(){
+        settings.setPath(storagePath);
+        settings.setDicoogleDir(dicoogleDir);
+        settings.setIndexerEffort(effort);
+        settings.setSaveThumbnails(saveTumbnails);
+        settings.setThumbnailsMatrix(thumbnailsMatrix);
+        settings.setIndexZIPFiles(saveTumbnails);
+        settings.setIndexZIPFiles(indezZip);
+        settings.setGzipStorage(gzipStorage);
+        settings.setMonitorWatcher(isMonitorWatcher());
+        settings.setIndexAnonymous(indexAnonymous);
+    }
+
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != ServerSettings)
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+        
+        if(!storagePath.equals(settings.getPath()) || !dicoogleDir.equals(settings.getDicoogleDir()) ||
+                effort != settings.getIndexerEffort() || saveTumbnails != settings.getSaveThumbnails() ||
+                monitorWatcher != settings.isMonitorWatcher() || 
+                indezZip != settings.isIndexZIPFiles() || 
+                indexAnonymous != settings.isIndexAnonymous() || 
+                !thumbnailsMatrix.equals(settings.getThumbnailsMatrix()))
+            return true;
+
+        return false;
+    }
+
+    /**
+     *
+     * @param path
+     * @return  0 - Ok
+     *          1 - Not a directory
+     *          2 - Can't read
+     *          3 - Can't write
+     * @throws RemoteException
+     */
+    @Override
+    public int setStoragePath(String path) throws RemoteException {
+        File file = new File(path);
+
+        if(!file.isDirectory())
+            return 1;
+
+        if(!file.canRead())
+            return 2;
+
+        if(!file.canWrite())
+            return 3;
+
+        storagePath = path;
+        
+        return 0;
+    }
+
+    @Override
+    public String getStoragePath() throws RemoteException {
+        return storagePath;
+    }
+
+    @Override
+    public int setDicoogleDir(String path) throws RemoteException {
+        File file = new File(path);
+
+        if(!file.isDirectory())
+            return 1;
+
+        if(!file.canRead())
+            return 2;
+
+        if(!file.canWrite())
+            return 3;
+
+        dicoogleDir = path;
+
+        return 0;
+    }
+
+    @Override
+    public String getDicoogleDir() throws RemoteException {
+        return dicoogleDir;
+    }
+
+    @Override
+    public boolean setIndexerEffort(int effort) throws RemoteException {
+        if(effort < 0 || effort > 100)
+            return false;
+
+        this.effort = effort;
+        
+        return true;
+    }
+
+    @Override
+    public int getIndexerEffort() throws RemoteException {
+        return effort;
+    }
+
+    @Override
+    public void setSaveThumbnails(boolean value) throws RemoteException {
+        saveTumbnails = value;
+    }
+
+    @Override
+    public boolean getSaveThumbnails() throws RemoteException {
+        return saveTumbnails;
+    }
+
+    @Override
+    public void setThumbnailsMatrix(String ThumbnailsMatrix) throws RemoteException {
+        thumbnailsMatrix = ThumbnailsMatrix;
+    }
+
+    @Override
+    public String getThumbnailsMatrix() throws RemoteException {
+        return thumbnailsMatrix;
+    }
+
+
+    /**
+     *
+     * @return  0 - OK
+     *          1 - Defined storage path is invalid
+     *          2 - Server running
+     * @throws RemoteException
+     */
+    @Override
+    public int rebuildIndex() throws RemoteException {
+        saveSettings();
+        
+        ControlServices serv = ControlServices.getInstance();
+
+        if (!serv.storageIsRunning()) {
+            File f = new File(storagePath);
+            //DebugManager.getInstance().debug("Rebuild Search Index on: " + f.getAbsolutePath());
+            
+            if (!f.exists()) {
+                return 1;
+            }
+
+            try {
+                PluginController.getInstance().index(new URI(f.getAbsolutePath()));
+            } catch (URISyntaxException ex) {
+                logger.error(ex.getMessage(), ex);
+            }
+            
+        } else
+            return 2;
+
+        return 0;
+    }
+
+
+    /**
+     *
+     * @return  0 - OK
+     *          1 - Defined storage path is invalid
+     *          2 - Server running
+     * @throws RemoteException
+     */
+    @Override
+    public int rebuildDICOMDir() throws RemoteException {
+        saveSettings();
+
+        ControlServices serv = ControlServices.getInstance();
+
+        if (!serv.storageIsRunning()) {
+            File f = new File(dicoogleDir);
+            //DebugManager.getInstance().debug(f.getAbsolutePath());
+
+            if (!f.exists()) {
+                return 1;
+            }
+
+            DicomDirCreator dirc = new DicomDirCreator(dicoogleDir, "Dicoogle");
+            dirc.dicomdir_rebuild();
+        } else
+            return 2;
+
+        return 0;
+    }
+
+    @Override
+    public boolean isIndexZip() throws RemoteException
+    {
+        return indezZip;
+    }
+
+
+    @Override
+    public void setIndexZip(boolean value) throws RemoteException {
+        indezZip = value;
+    }
+
+    /**
+     * @return the monitorWatcher
+     */
+    public boolean isMonitorWatcher() {
+        return monitorWatcher;
+    }
+
+    /**
+     * @param monitorWatcher the monitorWatcher to set
+     */
+    public void setMonitorWatcher(boolean monitorWatcher) {
+        this.monitorWatcher = monitorWatcher;
+    }
+
+    @Override
+    public boolean isIndexAnonymous() throws RemoteException {
+        return this.indexAnonymous;
+    }
+
+    @Override
+    public void setIndexAnonymous(boolean value) throws RemoteException {
+        this.indexAnonymous = value;
+    }
+
+    @Override
+    public boolean isGZipStorage() throws RemoteException {
+        return this.gzipStorage;
+    }
+
+    @Override
+    public void setGZipStorage(boolean value) throws RemoteException {
+        this.gzipStorage = value;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/IndexOptions.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/IndexOptions.java
new file mode 100755
index 0000000..afe024c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/IndexOptions.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.Semaphore;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.core.TagsXML;
+import pt.ua.dicoogle.core.dicom.PrivateDictionary;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IIndexOptions;
+import pt.ua.dicoogle.rGUI.server.DicoogleScan;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ * Controller of Index Options Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class IndexOptions implements IIndexOptions {
+
+    //private HashMap<Integer, TagValue> dimFields;
+    //private ArrayList<String> modalities;
+    //private HashMap<Integer, TagValue> manualFields;
+    private boolean isIndexAllModalities;
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static IndexOptions instance = null;
+
+    private TagsStruct tags = TagsStruct.getInstance();
+    private boolean saved = true;
+
+    public static synchronized IndexOptions getInstance()
+    {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new IndexOptions();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+    
+    private IndexOptions(){
+        loadSettings(); 
+    }
+
+    /**
+     * Load settings from TagsStruct
+     */
+    public void loadSettings(){
+        isIndexAllModalities = tags.isIndexAllModalitiesEnabled();
+    }
+
+    /**
+     * Save the Settings related to IndexOptions (TagsStruct)
+     *
+     * Print TagsXML
+     */
+    public void saveSettings(){
+    	saved = true;
+        tags.enableIndexAllModalities(isIndexAllModalities);
+
+        // Flush to XML file
+        TagsXML ts = new TagsXML();
+        ts.printXML();
+    }
+
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != TagsStruct)
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+    	return saved;
+    }
+
+    @Override
+    public HashMap<String, ArrayList<TagValue>> getDIMFields() throws RemoteException {
+        //DebugManager.getInstance().debug("Getting DIM Fields");        
+        /** Get groups **/
+        HashMap<String, ArrayList<TagValue>> groupTable = new HashMap<String, ArrayList<TagValue>>();      
+        for(TagValue tag : tags.getDIMFields()){
+            if (groupTable.containsKey(tag.getGroup())) {
+                groupTable.get(tag.getGroup()).add(tag);
+
+            } else {
+                ArrayList<TagValue> temp = new ArrayList<TagValue>();
+                temp.add(tag);
+                groupTable.put(tag.getGroup(), temp);
+            }
+        }
+        
+        return groupTable;
+    }
+
+    @Override
+    public ArrayList<String> getModalities() throws RemoteException {
+    	ArrayList<String> arr = new ArrayList<>(tags.getModalities());    	
+        return arr;
+    }
+
+    @Override
+    public boolean addModality(String modality) throws RemoteException {
+    	saved = false;
+    	boolean r = !tags.containsModality(modality);
+    	tags.addModality(modality);
+    	return r;
+    }
+
+    @Override
+    public boolean removeModality(String modality) throws RemoteException {
+    	saved = false;
+    
+        return tags.removeModality(modality);
+    }
+
+    @Override
+    public HashMap<String, ArrayList<TagValue>> getManualFields() throws RemoteException {
+        /** Get groups **/
+        HashMap<String, ArrayList<TagValue>> groupTable = new HashMap<String, ArrayList<TagValue>>();
+        for (TagValue tag : tags.getOtherFields()) {
+            //DebugManager.getInstance().debug(">> Grouping the Others Tags in MainWindow Notebook");
+
+            if (groupTable.containsKey(tag.getGroup())) {
+                groupTable.get(String.valueOf(tag.getGroup())).add(tag);
+
+            } else {
+                ArrayList<TagValue> temp = new ArrayList<TagValue>();
+                temp.add(tag);
+                groupTable.put(tag.getGroup(), temp);
+            }
+        }
+
+        return groupTable;
+    }
+
+    @Override
+    public boolean addManualField(int group, int subGroup, String name) throws RemoteException {
+    	saved = false;
+        String tag = String.valueOf(group) + String.valueOf(subGroup);
+        TagValue t = new TagValue(Integer.parseInt(tag, 16), name);       
+        
+        return tags.addPrivateField(t);
+    }
+
+    @Override
+    public boolean removeManualField(int group, int subGroup) throws RemoteException {
+    	saved = false;
+        String tag = String.valueOf(group) + String.valueOf(subGroup);
+
+        return tags.removePrivateField(Integer.parseInt(tag, 16));
+    }
+
+    @Override
+    public boolean isIndexAllModalities() throws RemoteException {
+        return isIndexAllModalities;
+    }
+
+    @Override
+    public void setIndexAllModalities(boolean value) throws RemoteException {
+    	saved = false;
+        isIndexAllModalities = value;
+    }
+
+
+
+
+    /**
+     * Index new file or folder
+     *
+     * @param Path - file or folter path
+     * @throws RemoteException
+     */
+    @Override
+    public void index(String Path, boolean resume) throws RemoteException {
+        Logs.getInstance().addServerLog("Start indexing: " + Path);
+        
+        DicoogleScan scandir = new DicoogleScan(Path);
+        scandir.scan(resume);
+    }
+
+    /**
+     * Indexes even if the file is already indexed
+     *
+     * @param path
+     * @throws RemoteException
+     */
+    @Override
+    public void reIndex(ArrayList<String> list) throws RemoteException {
+        Logs.getInstance().addServerLog("Start reIndexing " + list.size() + " file(s)");
+        
+        class REIndex extends Thread{
+            private ArrayList<String> list;
+
+            public REIndex(ArrayList<String> list){
+                this.list = list;
+            }
+
+            @Override
+            public void run(){
+                for(String Path: list)
+                    try {
+                        PluginController.getInstance().index(new URI(Path));
+                    } catch (URISyntaxException ex) {
+                        LoggerFactory.getLogger(DirectorySettings.class).error(ex.getMessage(), ex);
+                    }
+            }
+        }
+
+        //reIndex all files
+        (new REIndex(list)).start();
+    }
+
+    @Override
+    public void removeFilesFromIndexer(ArrayList<String> files, boolean deleteFiles) throws RemoteException {
+        Logs.getInstance().addServerLog("Start removing " + files.size() + " file(s)");
+
+        class DeleteFiles extends Thread{
+            private ArrayList<String> list;
+            private boolean delete;
+
+            public DeleteFiles(ArrayList<String> list, boolean delete){
+                this.list = list;
+                this.delete = delete;
+            }
+
+            @Override
+            public void run(){
+                for(String Path: list)
+                {
+                    try {
+                        PluginController.getInstance().index(new URI(Path));
+                    } catch (URISyntaxException ex) {
+                        LoggerFactory.getLogger(DirectorySettings.class).error(ex.getMessage(), ex);
+                    }
+                
+                    if (delete)
+                    {
+                        
+                        File f = new File(Path);
+                        f.delete();
+                    }
+                }
+            }
+        }
+
+        (new DeleteFiles(files, deleteFiles)).start();
+
+    }
+
+    @Override
+    public boolean removeDictionary(String dic) throws RemoteException {
+        
+        TagsStruct.getInstance().removeDicionary(dic);
+        
+        return true;
+        
+    }
+
+    @Override
+    public boolean addDictionary(String dic) throws RemoteException {
+        
+        TagsStruct.getInstance().addDicionary(dic);
+        PrivateDictionary pd = new PrivateDictionary();
+        pd.parse(dic);
+        return true;
+        
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Logs.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Logs.java
new file mode 100755
index 0000000..0ec820c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Logs.java
@@ -0,0 +1,251 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.rmi.RemoteException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.TimerTask;
+import java.util.concurrent.Semaphore;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ILogs;
+import pt.ua.dicoogle.DicomLog.LogDICOM;
+import pt.ua.dicoogle.DicomLog.LogLine;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ILogsSignal;
+import pt.ua.dicoogle.server.users.UserSessionsLog;
+import pt.ua.dicoogle.server.FileWatcher;
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ * Controller of Logs
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class Logs implements ILogs {
+    // Server Log (activities in server)
+
+    private static String logfilename;
+    private static File logfile;
+    private ILogsSignal signalBack;
+
+    private String serverLog;
+    private static Semaphore sem = new Semaphore(1, true);
+    private static Logs instance = null;
+
+    // saves the Loglines that are pending to send to GUI client
+    private ArrayList<LogLine> partialDICOMLog;
+    private String partialServerLog;
+
+    public static synchronized Logs getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new Logs();
+            }
+            sem.release();
+
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(Logs.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private Logs() {
+
+        // defaul log file
+        logfilename = Platform.homePath() + "DICOMLOG.log";
+        logfile = new File(logfilename);
+
+        partialDICOMLog = new ArrayList<LogLine>();
+        partialServerLog = "";
+
+        /**
+         * File watcher of Log File, just to keep updated the
+         * interface log
+         */
+        TimerTask task = new FileWatcher(logfile) {
+
+            @Override
+            protected void onChange(File file) {
+                reloadtext(file);
+            }
+        };
+
+        java.util.Timer timer = new java.util.Timer();
+        // repeat the check every second
+        timer.schedule(task, new Date(), 1000);
+    }
+
+    public void resetSignalBack(){
+        signalBack = null;
+    }
+    
+    @Override
+    public void RegisterSignalBack(ILogsSignal signalBack) throws RemoteException {
+        this.signalBack = signalBack;
+        
+        try {
+            partialDICOMLog.addAll(LogDICOM.getInstance().getLl());
+            partialServerLog = UserSessionsLog.getInstance().readLog();
+
+            if(signalBack != null){
+                signalBack.sendLogSignal(0);
+                signalBack.sendLogSignal(2);
+            }
+        } catch (RemoteException ex) {
+            //Logger.getLogger(Logs.class.getName()).log(Level.SEVERE, null, ex);
+            //DebugManager.getInstance().debug("Problem sending signal to log: 4");
+        }
+        
+        serverLog = null;
+        reloadtext(logfile);
+    }
+
+
+    public void reloadtext(File file) {
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            int x = fis.available();
+            byte b[] = new byte[x];
+            fis.read(b);
+            String content = new String(b);
+            if (!content.equals(serverLog)) {
+                serverLog = content;
+
+                if(signalBack != null)
+                    signalBack.sendLogSignal(1);
+            }
+        } catch (IOException ex) {
+            //Logger.getLogger(Logs.class.getName()).log(Level.SEVERE, null, ex);
+            //DebugManager.getInstance().debug("Problem sending signal to log: 1");
+        }
+    }
+
+    public void addLog(LogLine line) {
+        partialDICOMLog.add(line);
+
+        try {
+            if(signalBack != null)
+                signalBack.sendLogSignal(0);
+        } catch (RemoteException ex) {
+            //Logger.getLogger(Logs.class.getName()).log(Level.SEVERE, null, ex);
+            //DebugManager.getInstance().debug("Problem sending signal to log: 2");
+        }
+    }
+
+    public void addServerLog(String text){
+        FileOutputStream fos = null;
+        PrintStream pos = null;
+        
+        try {
+            fos = new FileOutputStream(logfilename, true);
+            pos = new PrintStream(fos);
+            pos.print(getDateTime().concat(": ").concat(text).concat("\n"));
+
+            pos.close();
+            fos.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void addSessionsLog(String line){
+        partialServerLog = partialServerLog + line;
+
+        try {
+            if(signalBack != null)
+                signalBack.sendLogSignal(2);
+        } catch (RemoteException ex) {
+            //Logger.getLogger(Logs.class.getName()).log(Level.SEVERE, null, ex);
+            //DebugManager.getInstance().debug("Problem sending signal to log: 3");
+        }
+    }
+
+    @Override
+    public void clearDICOMLog() throws RemoteException {
+        partialDICOMLog.clear();
+        LogDICOM.getInstance().clearLog();
+
+        //DebugManager.getInstance().debug("Clear DICOM Log");
+    }
+
+    @Override
+    public void clearServerLog() throws RemoteException {
+        FileOutputStream fos = null;
+        PrintStream pos = null;
+
+        /*
+         * To clear the log, writes an empty string to the logfile
+         */
+        try {
+            fos = new FileOutputStream(logfilename);
+            pos = new PrintStream(fos);
+            pos.print("");
+
+            pos.close();
+            fos.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void clearSessionsLog() throws RemoteException {
+        partialServerLog = "";
+        UserSessionsLog.getInstance().cleanLog();
+    }
+
+    @Override
+    public ArrayList<LogLine> getPendingDICOMLog() throws RemoteException {
+        ArrayList<LogLine> log = new ArrayList<LogLine>(partialDICOMLog);
+
+        partialDICOMLog.clear();
+        
+        return log;
+    }
+
+    @Override
+    public String getServerLog() throws RemoteException {
+        return serverLog;
+    }
+
+    @Override
+    public String getPendingSessionsLog() throws RemoteException {
+        String tmp =  partialServerLog;
+
+        partialServerLog = "";
+
+        return tmp;
+    }
+
+    private String getDateTime() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        Date date = new Date();
+        return dateFormat.format(date);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/NetworkInterfaces.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/NetworkInterfaces.java
new file mode 100755
index 0000000..b805fba
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/NetworkInterfaces.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.INetworkInterfaces;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public class NetworkInterfaces implements INetworkInterfaces
+{
+    private ServerSettings settings;
+    private static Semaphore sem = new Semaphore(1, true);
+    private static NetworkInterfaces instance = null;
+
+    public static synchronized NetworkInterfaces getInstance()
+    {
+        try
+        {
+            sem.acquire();
+            if (instance == null)
+            {
+                instance = new NetworkInterfaces();
+            }
+            sem.release();
+        } catch (InterruptedException ex)
+        {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private NetworkInterfaces()
+    {
+        settings = ServerSettings.getInstance();
+    }
+
+    @Override
+    public ArrayList<String> getNetworkInterfaces() throws RemoteException
+    {
+        return this.settings.getNetworkInterfacesNames();
+    }
+
+    @Override
+    public void setNetworkInterface(String name) throws RemoteException
+    {
+        if(name != null)
+        {
+            //System.out.println("interface chosen: " + name);
+            this.settings.setNetworkInterfaceName(name);
+        }
+    }
+
+    @Override
+    public String getNetworkInterface() throws RemoteException
+    {
+        return this.settings.getNetworkInterfaceName();
+    }
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PendingMessages.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PendingMessages.java
new file mode 100755
index 0000000..56e7eb6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PendingMessages.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPendingMessages;
+import pt.ua.dicoogle.rGUI.interfaces.signals.IPendingMessagesSignal;
+
+/**
+ * Controller to manage the pending messages to the administrator
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class PendingMessages implements IPendingMessages {
+
+    private IPendingMessagesSignal signal;
+
+    // list of files that are already indexed but the administrator as to decide if they will be re-indexed or not
+    private ArrayList<String> filesAlreadyIndexed;
+
+    /**
+     * I thought of using synchronized methods to take care of concurrency 
+     * in filesAlreadyIndexed ArrayList but this causes deadlock.
+     * I use Semaphore semList instead.
+     */
+    private static Semaphore semList = new Semaphore(1, true);
+    
+    private static PendingMessages instance = null;
+    private static Semaphore sem = new Semaphore(1, true);
+
+    public static synchronized PendingMessages getInstance()
+    {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new PendingMessages();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(PendingMessages.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private PendingMessages(){
+        filesAlreadyIndexed = new ArrayList<String>();
+    }
+
+
+    /**
+     * Add one file to the list of files already indexed
+     * 
+     * @param absolutePath
+     */
+    public void addFileAlreadyIndexed(String absolutePath){
+
+        try {
+            
+            semList.acquire();
+            filesAlreadyIndexed.add(absolutePath);
+            semList.release();
+            
+            try {
+                if (signal != null) {
+                    signal.sendPendingMessagesSignal(0);
+                }
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(PendingMessages.class).error(ex.getMessage(), ex);
+            }
+            
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(PendingMessages.class).error(ex.getMessage(), ex);
+        }
+        
+    }
+
+    /**
+     *
+     * @return the list of the files that are already indexed
+     * @throws RemoteException
+     */
+    @Override
+    public ArrayList<String> getFilesAlreadyIndexed() throws RemoteException {
+        try {
+            semList.acquire();
+
+            ArrayList<String> temp = filesAlreadyIndexed;
+            filesAlreadyIndexed = new ArrayList<String>();
+
+            semList.release();
+
+            return temp;
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(PendingMessages.class).error(ex.getMessage(), ex);
+            return null;
+        }
+    }
+
+    /**
+     * Register the remote signal object to send pending messages
+     *
+     * @param signalBack
+     * @throws RemoteException
+     */
+    @Override
+    public void RegisterSignalBack(IPendingMessagesSignal signalBack) throws RemoteException {
+        if (signalBack != null){
+            signal = signalBack;
+
+            if(filesAlreadyIndexed.size() > 0)
+                signal.sendPendingMessagesSignal(0);
+        }
+    }
+
+    public void resetSignalBack(){
+        signal = null;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4Admin.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4Admin.java
new file mode 100644
index 0000000..f015b65
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4Admin.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerAdmin;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public class PluginController4Admin implements IPluginControllerAdmin
+{
+    private static PluginController4Admin instance = null;
+
+    private PluginController4Admin()
+    {
+    }
+
+    public static PluginController4Admin getInstance()
+    {
+        if(PluginController4Admin.instance == null)
+        {
+            PluginController4Admin.instance = new PluginController4Admin();
+        }
+        return PluginController4Admin.instance;
+    }
+
+    @Override
+    public synchronized List<String> getPluginNames() throws RemoteException
+    {
+        //ok, this desperatly needs fixing...
+    	//return null;
+        return new ArrayList();
+        //TODO DELETED
+        //return PluginController.getInstance().getPluginsNames();
+    }
+
+    @Override
+    public synchronized void setSettings(HashMap<String, ArrayList> settings) throws RemoteException
+    {
+
+    	return ;
+        //TODO DELETED
+        //PluginController.getInstance().setSettings(settings);
+    }
+
+    @Override
+    public void InitiatePlugin(String PluginName) throws RemoteException
+    {
+
+    	return ;
+        //TODO DELETED
+        //PluginController.getInstance().initializePlugin(PluginName);
+    }
+
+    @Override
+    public void StopPlugin(String PluginName) throws RemoteException
+    {
+        PluginController.getInstance().stopPlugin(PluginName);
+    }
+
+    @Override
+    public boolean isRunning(String PluginName) throws RemoteException
+    {
+
+    	return false;
+        //TODO DELETED
+        //return PluginController.getInstance().isPluginRunning(PluginName);
+    }
+
+    @Override
+    public boolean isLocalPlugin(String PluginName) throws RemoteException
+    {
+
+    	return false;
+        //TODO DELETED
+       // return PluginController.getInstance().isLocalPlugin(PluginName);
+    }
+
+    @Override
+    public HashMap<String, ArrayList> getInitializeParams() throws RemoteException
+    {
+
+    	return null;
+        //TODO DELETED
+       // return PluginController.getInstance().getPanelInitialParams();
+    }
+
+    @Override
+    public byte[] getJarFile(String PluginName) throws RemoteException
+    {
+    	return null;
+        //TODO DELETED
+        //return PluginController.getInstance().getJarFile(PluginName);
+    }
+
+    @Override
+    public void saveSettings() throws RemoteException
+    {
+
+    	return ;
+        //TODO DELETED
+       //PluginController.getInstance().saveSettings();
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4user.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4user.java
new file mode 100755
index 0000000..277f556
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/PluginController4user.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IPluginControllerUser;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+ at Deprecated
+public class PluginController4user implements IPluginControllerUser
+{
+    private static PluginController4user instance = null;
+    
+    private PluginController4user()
+    {
+    }
+
+    public static PluginController4user getInstance()
+    {
+        if(PluginController4user.instance == null)
+        {
+            PluginController4user.instance = new PluginController4user();
+        }
+        return PluginController4user.instance;
+    }
+    
+    @Override
+    public synchronized List<String> getPluginNames() throws RemoteException
+    {
+    	return PluginController.getInstance().getQueryProvidersName(true);
+        //return PluginController.getInstance().getPluginsNames();
+    	//TODO: DELETED
+    }
+
+    @Override
+    public boolean isRunning(String PluginName) throws RemoteException
+    {
+    	return false;
+//        
+//        return PluginController.getInstance().isPluginRunning(PluginName);
+//        TODO: DELETED
+    }
+
+    @Override
+    public boolean isLocalPlugin(String PluginName) throws RemoteException
+    {
+    	return false;
+        
+//        return PluginController.getInstance().isLocalPlugin(PluginName);
+//        TODO: DELETED
+    }
+
+    @Override
+    public List<JPanel> getTabPanels() throws RemoteException{
+        return PluginController.getInstance().getTabItems();
+    }
+
+    @Override
+    public List<String> getGraphicPluginNames() throws RemoteException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public List<JMenuItem> getRightButtonItems() throws RemoteException {
+        return PluginController.getInstance().getRightButtonItems();
+    }
+    
+    @Override
+    public List<JMenuItem> getPluginMenus() throws RemoteException{
+        return PluginController.getInstance().getMenuItems();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QRServers.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QRServers.java
new file mode 100755
index 0000000..9de4bb0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QRServers.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQRServers;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.core.ServerSettings;
+
+/**
+ * Controller of Query/Retrieve Servers Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class QRServers implements IQRServers {
+
+    private ServerSettings settings = null;
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static QRServers instance = null;
+
+
+    private ArrayList<MoveDestination> moves;
+    
+    public static synchronized QRServers getInstance()
+    {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new QRServers();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private QRServers(){
+        settings = ServerSettings.getInstance();
+
+        loadSettings();
+    }
+
+    public void loadSettings(){
+        moves = new ArrayList<MoveDestination>();
+        
+        moves.addAll(settings.getMoves());
+    }
+
+
+    /**
+     * Save the settings related to Startup Services
+     *
+     * not write the settings in XML
+     */
+    public void saveSettings(){
+        settings.setMoves(moves);
+    }
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != ServerSettings)
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+        if(!moves.equals(settings.getMoves()))
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Add one Query/Retrieve Server to the list
+     *
+     * @param move
+     * @return
+     */
+    @Override
+    public boolean AddEntry(MoveDestination move){
+
+        if(!moves.contains(move))
+        {
+            moves.add(move);
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean RemoveEntry(MoveDestination move){
+        return moves.remove(move);
+    }
+
+    @Override
+    public ArrayList<MoveDestination> getMoves(){
+        return moves;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QueryRetrieve.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QueryRetrieve.java
new file mode 100755
index 0000000..f6c0d02
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/QueryRetrieve.java
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IQueryRetrieve;
+
+/**
+ * Controller of Query/Retrieve Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class QueryRetrieve implements IQueryRetrieve {
+    private ServerSettings settings;
+
+    private int MaxClientAssoc;
+    private int MaxPDULengthReceive;
+    private int MaxPDULengthSend;
+    private int IdleTimeout;
+    private int AcceptTimeout;
+    private int RspDelay;
+    private int ConnectionTimeout;
+
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static QueryRetrieve instance = null;
+
+    public static synchronized QueryRetrieve getInstance()
+    {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new QueryRetrieve();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private QueryRetrieve(){
+        settings = ServerSettings.getInstance();
+
+        loadSettings();
+    }
+
+    public void loadSettings(){
+        MaxClientAssoc = settings.getMaxClientAssoc();
+        MaxPDULengthReceive = settings.getMaxPDULengthReceive();
+        MaxPDULengthSend = settings.getMaxPDULenghtSend();
+        IdleTimeout = settings.getIdleTimeout();
+        AcceptTimeout = settings.getAcceptTimeout();
+        RspDelay = settings.getRspDelay();
+        ConnectionTimeout = settings.getConnectionTimeout();
+    }
+
+    /**
+     * Save the Settings related to QueryRetrieve to ServerSettings
+     *
+     * dont print XML
+     */
+    public void saveSettings(){
+        settings.setMaxClientAssoc(MaxClientAssoc);
+        settings.setMaxPDULengthReceive(MaxPDULengthReceive);
+        settings.setMaxPDULengthSend(MaxPDULengthSend);
+        settings.setIdleTimeout(IdleTimeout);
+        settings.setAcceptTimeout(AcceptTimeout);
+        settings.setRspDelay(RspDelay);
+        settings.setConnectionTimeout(ConnectionTimeout);
+    }
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != ServerSettings)
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+        if(MaxClientAssoc != settings.getMaxClientAssoc() || MaxPDULengthReceive != settings.getMaxPDULengthReceive()
+                || MaxPDULengthSend != settings.getMaxPDULenghtSend() || IdleTimeout != settings.getIdleTimeout()
+                || AcceptTimeout != settings.getAcceptTimeout() || RspDelay != settings.getRspDelay()
+                || ConnectionTimeout != settings.getConnectionTimeout())
+            return true;
+
+        return false;
+    }
+
+    @Override
+    public int getMaxClientAssoc() throws RemoteException {
+        return MaxClientAssoc;
+    }
+    @Override
+    public void setMaxClientAssoc(int value) throws RemoteException {
+        MaxClientAssoc = value;
+    }
+
+    @Override
+    public int getMaxPDULengthReceive() throws RemoteException {
+        return MaxPDULengthReceive;
+    }
+    @Override
+    public void setMaxPDULengthReceive(int value) throws RemoteException {
+        MaxPDULengthReceive = value;
+    }
+
+    @Override
+    public int getMaxPDULengthSend() throws RemoteException {
+        return MaxPDULengthSend;
+    }
+    @Override
+    public void setMaxPDULengthSend(int value) throws RemoteException {
+        MaxPDULengthSend = value;
+    }
+
+    @Override
+    public int getQRIdleTimeout() throws RemoteException {
+        return IdleTimeout;
+    }
+    @Override
+    public void setQRIdleTimeout(int value) throws RemoteException {
+        IdleTimeout = value;
+    }
+
+    @Override
+    public int getQRAcceptTimeout() throws RemoteException {
+        return AcceptTimeout;
+    }
+    @Override
+    public void setQRAcceptTimeout(int value) throws RemoteException {
+        AcceptTimeout = value;
+    }
+
+    @Override
+    public int getQRRspDelay() throws RemoteException {
+        return RspDelay;
+    }
+    @Override
+    public void setQRRspDelay(int value) throws RemoteException {
+        RspDelay = value;
+    }
+
+    @Override
+    public int getQRConnectionTimeout() throws RemoteException {
+        return ConnectionTimeout;
+    }
+    @Override
+    public void setQRConnectionTimeout(int value) throws RemoteException {
+        ConnectionTimeout = value;
+    }
+
+    @Override
+    public HashMap<String, String> getFindModalities() throws RemoteException {
+        Map<String, String> map = settings.getModalityFind();
+        
+        return new HashMap<String, String>(map);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/SOPClass.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/SOPClass.java
new file mode 100755
index 0000000..66ea74a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/SOPClass.java
@@ -0,0 +1,563 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.dcm4che2.data.UID;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISOPClass;
+import pt.ua.dicoogle.server.SOPList;
+import pt.ua.dicoogle.server.TransfersStorage;
+
+/**
+ * Controller of SOP Class Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class SOPClass implements ISOPClass {
+
+    private SOPList list;
+    private TransfersStorage localTS;
+    
+    private ArrayList<String> SOPClassList;
+    private ArrayList<SimpleEntry<String, String>> TS;
+    private static Semaphore sem = new Semaphore(1, true);
+    private static SOPClass instance = null;
+
+    public static synchronized SOPClass getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new SOPClass();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(QRServers.class).error(ex.getMessage(), ex);
+        }
+        return instance;
+    }
+
+    private SOPClass() {
+
+        list = SOPList.getInstance();
+        
+        initSOPClassList();
+        initTS();
+    }
+
+    private void initTS() {
+        TS = new ArrayList<SimpleEntry<String, String>>();
+
+        TS.add(new SimpleEntry(UID.ImplicitVRLittleEndian, "ImplicitVRLittleEndian"));
+        TS.add(new SimpleEntry(UID.ExplicitVRLittleEndian, "ExplicitVRLittleEndian"));
+        TS.add(new SimpleEntry(UID.DeflatedExplicitVRLittleEndian, "DeflatedExplicitVRLittleEndian"));
+        TS.add(new SimpleEntry(UID.ExplicitVRBigEndian, "ExplicitVRBigEndian"));
+        TS.add(new SimpleEntry(UID.JPEGLossless, "JPEG Lossless"));
+        TS.add(new SimpleEntry(UID.JPEGLSLossless, "JPEG Lossless LS"));
+        TS.add(new SimpleEntry(UID.JPEGLosslessNonHierarchical14, "JPEG Lossless, Non-Hierarchical (Process 14) "));
+        TS.add(new SimpleEntry(UID.JPEG2000LosslessOnly, "JPEG2000 Lossless Only"));
+        TS.add(new SimpleEntry(UID.JPEGBaseline1, "JPEG Baseline 1"));
+        TS.add(new SimpleEntry(UID.JPEGExtended24, "JPEG Extended (Process 2 & 4)"));
+        TS.add(new SimpleEntry(UID.JPEGLSLossyNearLossless, "JPEG LS Lossy Near Lossless"));
+        TS.add(new SimpleEntry(UID.JPEG2000, "JPEG2000"));
+        TS.add(new SimpleEntry(UID.RLELossless, "RLE Lossless"));
+        TS.add(new SimpleEntry(UID.MPEG2, "MPEG2"));
+    }
+
+    private void initSOPClassList() {
+        SOPClassList = new ArrayList<String>();
+
+        SOPClassList.add("BasicStudyContentNotification (Retired)");
+        SOPClassList.add("StoredPrintStorage (Retired)");
+        SOPClassList.add("HardcopyGrayscaleImageStorage (Retired)");
+        SOPClassList.add("HardcopyColorImageStorage (Retired)");
+        SOPClassList.add("ComputedRadiographyImageStorage");
+        SOPClassList.add("DigitalXRayImageStorageForPresentation");
+        SOPClassList.add("DigitalXRayImageStorageForProcessing");
+        SOPClassList.add("DigitalMammographyXRayImageStorageForPresentation");
+        SOPClassList.add("DigitalMammographyXRayImageStorageForProcessing");
+        SOPClassList.add("DigitalIntraoralXRayImageStorageForPresentation");
+        SOPClassList.add("DigitalIntraoralXRayImageStorageForProcessing");
+        SOPClassList.add("StandaloneModalityLUTStorage (Retired)");
+        SOPClassList.add("EncapsulatedPDFStorage");
+        SOPClassList.add("StandaloneVOILUTStorage (Retired)");
+        SOPClassList.add("GrayscaleSoftcopyPresentationStateStorage");
+        SOPClassList.add("ColorSoftcopyPresentationStateStorage");
+        SOPClassList.add("PseudoColorSoftcopyPresentationStateStorage");
+        SOPClassList.add("BlendingSoftcopyPresentationStateStorage");
+        SOPClassList.add("XRayAngiographicImageStorage");
+        SOPClassList.add("EnhancedXAImageStorage");
+        SOPClassList.add("XRayRadiofluoroscopicImageStorage");
+        SOPClassList.add("EnhancedXRFImageStorage");
+        SOPClassList.add("XRayAngiographicBiPlaneImageStorage (Retired)");
+        SOPClassList.add("PositronEmissionTomographyImageStorage");
+        SOPClassList.add("StandalonePETCurveStorage (Retired)");
+        SOPClassList.add("CTImageStorage");
+        SOPClassList.add("EnhancedCTImageStorage");
+        SOPClassList.add("NuclearMedicineImageStorage");
+        SOPClassList.add("UltrasoundMultiframeImageStorage (Retired)");
+        SOPClassList.add("UltrasoundMultiframeImageStorage");
+        SOPClassList.add("MRImageStorage");
+        SOPClassList.add("EnhancedMRImageStorage");
+        SOPClassList.add("MRSpectroscopyStorage");
+        SOPClassList.add("RTImageStorage");
+        SOPClassList.add("RTDoseStorage");
+        SOPClassList.add("RTStructureSetStorage");
+        SOPClassList.add("RTBeamsTreatmentRecordStorage");
+        SOPClassList.add("RTPlanStorage");
+        SOPClassList.add("RTBrachyTreatmentRecordStorage");
+        SOPClassList.add("RTTreatmentSummaryRecordStorage");
+        SOPClassList.add("NuclearMedicineImageStorage (Retired)");
+        SOPClassList.add("UltrasoundImageStorage (Retired)");
+        SOPClassList.add("UltrasoundImageStorage");
+        SOPClassList.add("RawDataStorage");
+        SOPClassList.add("SpatialRegistrationStorage");
+        SOPClassList.add("SpatialFiducialsStorage");
+        SOPClassList.add("RealWorldValueMappingStorage");
+        SOPClassList.add("SecondaryCaptureImageStorage");
+        SOPClassList.add("MultiframeSingleBitSecondaryCaptureImageStorage");
+        SOPClassList.add("MultiframeGrayscaleByteSecondaryCaptureImageStorage");
+        SOPClassList.add("MultiframeGrayscaleWordSecondaryCaptureImageStorage");
+        SOPClassList.add("MultiframeTrueColorSecondaryCaptureImageStorage");
+        SOPClassList.add("VLImageStorage (Retired)");
+        SOPClassList.add("VLEndoscopicImageStorage");
+        SOPClassList.add("VideoEndoscopicImageStorage");
+        SOPClassList.add("VLMicroscopicImageStorage");
+        SOPClassList.add("VideoMicroscopicImageStorage");
+        SOPClassList.add("VLSlideCoordinatesMicroscopicImageStorage");
+        SOPClassList.add("VLPhotographicImageStorage");
+        SOPClassList.add("VideoPhotographicImageStorage");
+        SOPClassList.add("OphthalmicPhotography8BitImageStorage");
+        SOPClassList.add("OphthalmicPhotography16BitImageStorage");
+        SOPClassList.add("StereometricRelationshipStorage");
+        SOPClassList.add("VLMultiframeImageStorage (Retired)");
+        SOPClassList.add("StandaloneOverlayStorage (Retired)");
+        SOPClassList.add("BasicTextSR");
+        SOPClassList.add("EnhancedSR");
+        SOPClassList.add("ComprehensiveSR");
+        SOPClassList.add("ProcedureLogStorage");
+        SOPClassList.add("MammographyCADSR");
+        SOPClassList.add("KeyObjectSelectionDocument");
+        SOPClassList.add("ChestCADSR");
+        SOPClassList.add("StandaloneCurveStorage (Retired)");
+        SOPClassList.add("12leadECGWaveformStorage");
+        SOPClassList.add("GeneralECGWaveformStorage");
+        SOPClassList.add("AmbulatoryECGWaveformStorage");
+        SOPClassList.add("HemodynamicWaveformStorage");
+        SOPClassList.add("CardiacElectrophysiologyWaveformStorage");
+        SOPClassList.add("BasicVoiceAudioWaveformStorage");
+        SOPClassList.add("HangingProtocolStorage");
+        SOPClassList.add("SiemensCSANonImageStorage");
+    }
+
+    /**
+     *
+     * @return the list with the names of SOP Classes
+     * @throws RemoteException
+     */
+    @Override
+    public ArrayList<String> getSOPClassList() throws RemoteException {
+        return SOPClassList;
+    }
+
+    @Override
+    public ArrayList<SimpleEntry<String, String>> getTransferSyntax() throws RemoteException {
+        return TS;
+    }
+
+    /**
+     * Get the UID from SOP Class Name
+     * @param sopClass
+     * @return UID corresponding to the SOP Class Name
+     * @throws RemoteException
+     */
+    @Override
+    public String getUID(String sopClass) throws RemoteException {
+        if(sopClass.equals("BasicStudyContentNotification (Retired)"))
+            return UID.BasicStudyContentNotificationSOPClassRetired;
+
+        if(sopClass.equals("StoredPrintStorage (Retired)"))
+            return UID.StoredPrintStorageSOPClassRetired;
+
+        if(sopClass.equals("HardcopyGrayscaleImageStorage (Retired)"))
+            return UID.HardcopyGrayscaleImageStorageSOPClassRetired;
+
+        if(sopClass.equals("HardcopyColorImageStorage (Retired)"))
+            return UID.HardcopyColorImageStorageSOPClassRetired;
+
+        if(sopClass.equals("ComputedRadiographyImageStorage"))
+            return UID.ComputedRadiographyImageStorage;
+
+        if(sopClass.equals("DigitalXRayImageStorageForPresentation"))
+            return UID.DigitalXRayImageStorageForPresentation;
+
+
+        if(sopClass.equals("DigitalXRayImageStorageForProcessing"))
+            return UID.DigitalXRayImageStorageForProcessing;
+
+        if(sopClass.equals("DigitalMammographyXRayImageStorageForPresentation"))
+            return UID.DigitalMammographyXRayImageStorageForPresentation;
+
+        if(sopClass.equals("DigitalMammographyXRayImageStorageForProcessing"))
+            return UID.DigitalMammographyXRayImageStorageForProcessing;
+
+        if(sopClass.equals("DigitalIntraoralXRayImageStorageForPresentation"))
+            return UID.DigitalIntraOralXRayImageStorageForPresentation;
+
+        if(sopClass.equals("DigitalIntraoralXRayImageStorageForProcessing"))
+            return UID.DigitalIntraOralXRayImageStorageForProcessing;
+
+        if(sopClass.equals("StandaloneModalityLUTStorage (Retired)"))
+            return UID.StandaloneModalityLUTStorageRetired;
+
+        if(sopClass.equals("EncapsulatedPDFStorage"))
+            return UID.EncapsulatedPDFStorage;
+
+        if(sopClass.equals("StandaloneVOILUTStorage (Retired)"))
+            return UID.StandaloneVOILUTStorageRetired;
+
+        if(sopClass.equals("GrayscaleSoftcopyPresentationStateStorage"))
+            return UID.GrayscaleSoftcopyPresentationStateStorageSOPClass;
+
+        if(sopClass.equals("ColorSoftcopyPresentationStateStorage"))
+            return UID.ColorSoftcopyPresentationStateStorageSOPClass;
+        
+        if(sopClass.equals("PseudoColorSoftcopyPresentationStateStorage"))
+            return UID.PseudoColorSoftcopyPresentationStateStorageSOPClass;
+
+        if(sopClass.equals("BlendingSoftcopyPresentationStateStorage"))
+            return UID.BlendingSoftcopyPresentationStateStorageSOPClass;
+
+        if(sopClass.equals("XRayAngiographicImageStorage"))
+            return UID.XRayAngiographicImageStorage;
+
+        if(sopClass.equals("EnhancedXAImageStorage"))
+            return UID.EnhancedXAImageStorage;
+
+        if(sopClass.equals("XRayRadiofluoroscopicImageStorage"))
+            return UID.XRayRadiofluoroscopicImageStorage;
+
+        if(sopClass.equals("EnhancedXRFImageStorage"))
+            return UID.EnhancedXRFImageStorage;
+
+        if(sopClass.equals("XRayAngiographicBiPlaneImageStorage (Retired)"))
+            return UID.XRayAngiographicBiPlaneImageStorageRetired;
+
+        if(sopClass.equals("PositronEmissionTomographyImageStorage"))
+            return UID.PositronEmissionTomographyImageStorage;
+
+        if(sopClass.equals("StandalonePETCurveStorage (Retired)"))
+            return UID.StandalonePETCurveStorageRetired;
+
+        if(sopClass.equals("CTImageStorage"))
+            return UID.CTImageStorage;
+
+        if(sopClass.equals("EnhancedCTImageStorage"))
+            return UID.EnhancedCTImageStorage;
+
+        if(sopClass.equals("NuclearMedicineImageStorage"))
+            return UID.NuclearMedicineImageStorage;
+
+        if(sopClass.equals("UltrasoundMultiframeImageStorage (Retired)"))
+            return UID.UltrasoundMultiFrameImageStorageRetired;
+
+        if(sopClass.equals("UltrasoundMultiframeImageStorage"))
+            return UID.UltrasoundMultiFrameImageStorage;
+
+        if(sopClass.equals("MRImageStorage"))
+            return UID.MRImageStorage;
+
+        if(sopClass.equals("EnhancedMRImageStorage"))
+            return UID.EnhancedMRImageStorage;
+
+        if(sopClass.equals("MRSpectroscopyStorage"))
+            return UID.MRSpectroscopyStorage;
+
+        if(sopClass.equals("RTImageStorage"))
+            return UID.RTImageStorage;
+
+        if(sopClass.equals("RTDoseStorage"))
+            return UID.RTDoseStorage;
+
+        if(sopClass.equals("RTStructureSetStorage"))
+            return UID.RTStructureSetStorage;
+
+        if(sopClass.equals("RTBeamsTreatmentRecordStorage"))
+            return UID.RTBeamsTreatmentRecordStorage;
+
+        if(sopClass.equals("RTPlanStorage"))
+            return UID.RTPlanStorage;
+
+        if(sopClass.equals("RTBrachyTreatmentRecordStorage"))
+            return UID.RTBrachyTreatmentRecordStorage;
+
+        if(sopClass.equals("RTTreatmentSummaryRecordStorage"))
+            return UID.RTTreatmentSummaryRecordStorage;
+
+        if(sopClass.equals("NuclearMedicineImageStorage (Retired)"))
+            return UID.NuclearMedicineImageStorageRetired;
+
+        if(sopClass.equals("UltrasoundImageStorage (Retired)"))
+            return UID.UltrasoundImageStorageRetired;
+
+        if(sopClass.equals("UltrasoundImageStorage"))
+            return UID.UltrasoundImageStorage;
+
+        if(sopClass.equals("RawDataStorage"))
+            return UID.RawDataStorage;
+
+        if(sopClass.equals("SpatialRegistrationStorage"))
+            return UID.SpatialRegistrationStorage;
+
+        if(sopClass.equals("SpatialFiducialsStorage"))
+            return UID.SpatialFiducialsStorage;
+
+        if(sopClass.equals("RealWorldValueMappingStorage"))
+            return UID.RealWorldValueMappingStorage;
+
+        if(sopClass.equals("SecondaryCaptureImageStorage"))
+            return UID.SecondaryCaptureImageStorage;
+
+        if(sopClass.equals("MultiframeSingleBitSecondaryCaptureImageStorage"))
+            return UID.MultiFrameSingleBitSecondaryCaptureImageStorage;
+
+        if(sopClass.equals("MultiframeGrayscaleByteSecondaryCaptureImageStorage"))
+            return UID.MultiFrameGrayscaleByteSecondaryCaptureImageStorage;
+
+        if(sopClass.equals("MultiframeGrayscaleWordSecondaryCaptureImageStorage"))
+            return UID.MultiFrameGrayscaleWordSecondaryCaptureImageStorage;
+
+        if(sopClass.equals("MultiframeTrueColorSecondaryCaptureImageStorage"))
+            return UID.MultiFrameTrueColorSecondaryCaptureImageStorage;
+
+        if(sopClass.equals("VLImageStorage (Retired)"))
+            ///return UID.VLImageStorageRetired);
+            /** Update to new version from dcm4che */
+            return UID.VLImageStorageTrialRetired;
+
+        if(sopClass.equals("VLEndoscopicImageStorage"))
+            return UID.VLEndoscopicImageStorage;
+
+        if(sopClass.equals("VideoEndoscopicImageStorage"))
+            return UID.VideoEndoscopicImageStorage;
+
+        if(sopClass.equals("VLMicroscopicImageStorage"))
+            return UID.VLMicroscopicImageStorage;
+
+        if(sopClass.equals("VideoMicroscopicImageStorage"))
+            return UID.VideoMicroscopicImageStorage;
+
+        if(sopClass.equals("VLSlideCoordinatesMicroscopicImageStorage"))
+            return UID.VLSlideCoordinatesMicroscopicImageStorage;
+
+        if(sopClass.equals("VLPhotographicImageStorage"))
+            return UID.VLPhotographicImageStorage;
+
+        if(sopClass.equals("VideoPhotographicImageStorage"))
+            return UID.VideoPhotographicImageStorage;
+
+        if(sopClass.equals("OphthalmicPhotography8BitImageStorage"))
+            return UID.OphthalmicPhotography8BitImageStorage;
+
+        if(sopClass.equals("OphthalmicPhotography16BitImageStorage"))
+            return UID.OphthalmicPhotography16BitImageStorage;
+
+        if(sopClass.equals("StereometricRelationshipStorage"))
+            return UID.StereometricRelationshipStorage;
+
+        if(sopClass.equals("VLMultiframeImageStorage (Retired)"))
+            ///return UID.VLMultiframeImageStorageRetired);
+            /** Update to new version from dcm4che */
+            return UID.VLMultiFrameImageStorageTrialRetired;
+
+        if(sopClass.equals("StandaloneOverlayStorage (Retired)"))
+            return UID.StandaloneOverlayStorageRetired;
+
+        if(sopClass.equals("BasicTextSR"))
+            ///return UID.BasicTextSR);
+            /* update to new version from dcm4che */
+            return UID.BasicTextSRStorage;
+
+        if(sopClass.equals("EnhancedSR"))
+            ///return UID.EnhancedSR);
+            /* update to new version from dcm4che */
+            return UID.EnhancedSRStorage;
+
+        if(sopClass.equals("ComprehensiveSR"))
+            ///return UID.ComprehensiveSR);
+            /* update to new version from dcm4che */
+            return UID.ComprehensiveSRStorage;
+
+        if(sopClass.equals("ProcedureLogStorage"))
+            return UID.ProcedureLogStorage;
+
+        if(sopClass.equals("MammographyCADSR"))
+            ///return UID.MammographyCADSR);
+            /* update to new version from dcm4che */
+            return UID.MammographyCADSRStorage;
+
+        if(sopClass.equals("KeyObjectSelectionDocument"))
+            ///return UID.KeyObjectSelectionDocument);
+            /* update to new version from dcm4che */
+            return UID.MammographyCADSRStorage;
+
+        if(sopClass.equals("ChestCADSR"))
+            ///return UID.ChestCADSR);
+            /* update to new version from dcm4che */
+            return UID.ChestCADSRStorage;
+
+        if(sopClass.equals("StandaloneCurveStorage (Retired)"))
+            return UID.StandaloneCurveStorageRetired;
+
+        //if(sopClass.equals("12leadECGWaveformStorage"))
+            //return UID._12leadECGWaveformStorage;
+
+        if(sopClass.equals("GeneralECGWaveformStorage"))
+            return UID.GeneralECGWaveformStorage;
+
+        if(sopClass.equals("AmbulatoryECGWaveformStorage"))
+            return UID.AmbulatoryECGWaveformStorage;
+
+        if(sopClass.equals("HemodynamicWaveformStorage"))
+            return UID.HemodynamicWaveformStorage;
+
+        if(sopClass.equals("CardiacElectrophysiologyWaveformStorage"))
+            return UID.CardiacElectrophysiologyWaveformStorage;
+
+        if(sopClass.equals("BasicVoiceAudioWaveformStorage"))
+            return UID.BasicVoiceAudioWaveformStorage;
+
+        if(sopClass.equals("HangingProtocolStorage"))
+            return UID.HangingProtocolStorage;
+
+        if(sopClass.equals("SiemensCSANonImageStorage"))
+            return UID.SiemensCSANonImageStorage;
+        
+        return null;
+    }
+
+    @Override
+    public boolean[] getTS(String UID) throws RemoteException {
+        localTS = list.getTS(UID);
+        return localTS.getTS();
+    }
+
+    @Override
+    public boolean getAccepted(String UID) throws RemoteException {
+        localTS = list.getTS(UID);
+        return localTS.getAccepted();
+    }
+
+    @Override
+    public boolean[] setDefault() throws RemoteException {
+       localTS.setAccepted(true);
+       localTS.setTS(true,0);
+       localTS.setTS(true,1);
+       localTS.setTS(false,2);
+       localTS.setTS(false,3);
+       localTS.setTS(true,4);
+       localTS.setTS(false,5);
+       localTS.setTS(false,6);
+       localTS.setTS(false,7);
+       localTS.setTS(true,8);
+       localTS.setTS(false,9);
+       localTS.setTS(false,10);
+       localTS.setTS(false,11);
+       localTS.setTS(false,12);
+       localTS.setTS(false,13);
+
+       return localTS.getTS();
+    }
+
+    @Override
+    public boolean[] clearAll() throws RemoteException {
+       localTS.setAccepted(false);
+       localTS.setTS(false,0);
+       localTS.setTS(false,1);
+       localTS.setTS(false,2);
+       localTS.setTS(false,3);
+       localTS.setTS(false,4);
+       localTS.setTS(false,5);
+       localTS.setTS(false,6);
+       localTS.setTS(false,7);
+       localTS.setTS(false,8);
+       localTS.setTS(false,9);
+       localTS.setTS(false,10);
+       localTS.setTS(false,11);
+       localTS.setTS(false,12);
+       localTS.setTS(false,13);
+
+       return localTS.getTS();
+    }
+
+    @Override
+    public boolean[] setAll() throws RemoteException {
+       localTS.setAccepted(true);
+       localTS.setTS(true,0);
+       localTS.setTS(true,1);
+       localTS.setTS(true,2);
+       localTS.setTS(true,3);
+       localTS.setTS(true,4);
+       localTS.setTS(true,5);
+       localTS.setTS(true,6);
+       localTS.setTS(true,7);
+       localTS.setTS(true,8);
+       localTS.setTS(true,9);
+       localTS.setTS(true,10);
+       localTS.setTS(true,11);
+       localTS.setTS(true,12);
+       localTS.setTS(true,13);
+
+       return localTS.getTS();
+    }
+
+    @Override
+    public void setTS(String UID, boolean status, int number) throws RemoteException {
+        localTS = list.getTS(UID);
+
+        localTS.setTS(status, number);
+    }
+
+    @Override
+    public void saveLocalTS(String UID) throws RemoteException {
+        list.updateTS(UID, localTS.getTS(), localTS.getAccepted());
+    }
+
+    @Override
+    public void saveAllTS() throws RemoteException {
+        List l = list.getKeys();
+        for (int i = 0; i < l.size(); i++) {
+            list.updateTS(l.get(i).toString(), localTS.getTS(), localTS.getAccepted());
+        }
+    }
+
+    @Override
+    public void setAccepted(String UID, boolean value) throws RemoteException {
+        localTS = list.getTS(UID);
+        localTS.setAccepted(value);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Search.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Search.java
new file mode 100755
index 0000000..820332a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/Search.java
@@ -0,0 +1,517 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.rmi.server.RemoteServer;
+import java.util.*;
+import java.util.AbstractMap.SimpleEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.plugins.NetworkMember;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.rGUI.RFileBrowser.RemoteFile;
+import pt.ua.dicoogle.rGUI.fileTransfer.FileSender;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ISearch;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ISearchSignal;
+import pt.ua.dicoogle.rGUI.server.SearchHelper;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.FileObservable;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ *  This class is the controller to search in IndexEngine or P2P Network
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class Search implements ISearch
+{
+
+    private ISearchSignal searchSignal;
+    private ArrayList<String> extrafields;
+    private ArrayList<SearchResult> resultList;
+    private ArrayList<SearchResult> P2PResultList;
+    private ArrayList<SearchResult> pendingP2PThumbnails;
+    private ArrayList<SearchResult> exportList;
+    private SearchHelper searchHelper;
+    private long searchTime;
+
+    public Search()
+    {
+        extrafields = new ArrayList<String>();
+
+        extrafields.add("PatientName");
+        extrafields.add("PatientID");
+        extrafields.add("Modality");
+        extrafields.add("StudyDate");
+        extrafields.add("SOPInstanceUID");
+        //extrafields.add("Thumbnail");
+
+        searchHelper = new SearchHelper(this);
+    }
+
+    public void setSearchTime(long time)
+    {
+        searchTime = time;
+
+        /*
+        try {
+        if(searchSignal != null)
+        searchSignal.sendSearchSignal(2);
+        } catch (RemoteException ex) {
+        searchSignal = null;
+        DebugManager.getInstance().debug("Failure to send the signal to the client..");
+        LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+         * 
+         */
+    }
+
+    // SearchHelper sends the local searchResults
+    public void setLocalSearchResult(ArrayList<SearchResult> sResult)
+    {
+        this.resultList = sResult;
+
+        try
+        {
+            if (searchSignal != null)
+            {
+                searchSignal.sendSearchSignal(0);
+            }
+        } catch (RemoteException ex)
+        {
+            searchSignal = null;
+            //DebugManager.getInstance().debug("Failure to send the signal to the client..");
+            LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+    }
+    
+    
+    public void queryFinished()
+    {
+
+        try
+        {
+            if (searchSignal != null)
+            {
+                searchSignal.sendSearchSignal(5);
+            }
+        } catch (RemoteException ex)
+        {
+            searchSignal = null;
+            //DebugManager.getInstance().debug("Failure to send the signal to the client..");
+            LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    // SearchHelper sends the new P2P searchResults
+    public void setP2PSearchResult(ArrayList<SearchResult> sResult)
+    {
+        //System.out.println("entrou no setP2PSearchResult com " + sResult.size() + " resultados");
+        this.P2PResultList = sResult;
+        
+        try
+        {
+            if (searchSignal != null)
+            {
+                //System.out.println("there is searchsignal");
+                searchSignal.sendSearchSignal(1);
+            }
+        } catch (RemoteException ex)
+        {
+            searchSignal = null;
+            //DebugManager.getInstance().debug("Failure to send the signal to the client..");
+            LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    public void setExportSearchResult(ArrayList<SearchResult> sResult)
+    {
+        if (this.exportList != null)
+        {
+            exportList.addAll(sResult);
+        }
+        else
+        {
+            this.exportList = sResult;
+        }
+
+        try
+        {
+            
+            if (searchSignal != null)
+            {
+                searchSignal.sendSearchSignal(4);
+            }
+        } catch (RemoteException ex)
+        {
+            searchSignal = null;
+            //DebugManager.getInstance().debug("Failure to send the signal to the client..");
+            LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+        
+    }
+
+    public void setP2PThumbnails(ArrayList<SearchResult> sResult)
+    {
+        if (pendingP2PThumbnails != null)
+        {
+            pendingP2PThumbnails.addAll(sResult);
+        } else
+        {
+            pendingP2PThumbnails = sResult;
+        }
+
+        try
+        {
+            if (searchSignal != null)
+            {
+                searchSignal.sendSearchSignal(3);
+            }
+
+        } catch (RemoteException ex)
+        {
+            searchSignal = null;
+            //DebugManager.getInstance().debug("Failure to send the signal to the client..");
+            LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    
+    
+    @Override
+    public void Search(String query, boolean keywords, HashMap<String,Boolean> plugins) throws RemoteException
+
+    {
+        if (query.isEmpty())
+
+        {
+            query = "*:*";
+        } else
+        {
+            if (!keywords)
+            {
+                /**
+                 * Write the QueryString respecting BNF grammer
+                 * defined regarding Lucene documentation 2.4.X branch
+                 */
+                QueryExpressionBuilder _expression = new QueryExpressionBuilder(query);
+                query = _expression.getQueryString();
+            }
+            //DebugManager.getInstance().debug(">>> New Query String is:" + query);
+
+        }
+        searchTime = 0;
+        searchHelper.search(query, extrafields, plugins, false);
+    }
+
+    @Override
+    public ListObservableSearch<SearchResult> SearchToExport(String query, boolean keywords, HashMap<String, Boolean> plugins, ArrayList<String> eFields, Observer obs) throws RemoteException
+    {
+        if (query.isEmpty())
+        {
+            query = "*:*";
+        } else
+        {
+            if (!keywords)
+            {
+                QueryExpressionBuilder _expression = new QueryExpressionBuilder(query);
+                query = _expression.getQueryString();
+            }
+        }
+        
+        return searchHelper.search(query, eFields, plugins, true, obs);
+    
+    }
+
+    @Override
+    public void pruneQuery(String id) throws RemoteException
+    {
+        PluginController.getInstance().addTask(new TaskRequest(TaskRequestsConstants.T_QUERY_PRUNE, null, null));
+    }
+
+    class SearchDumper implements Observer
+    {
+
+        static final int WAIT_TIME = 10;
+        
+        ListObservableSearch<SearchResult> result = null;
+        
+        ArrayList<SearchResult> resultArr = new ArrayList<SearchResult>();
+        
+        public ArrayList<SearchResult> search(SearchResult r, String query, ArrayList<String> extrafields)
+        {
+        	return null;
+            /*synchronized(this)
+            {
+            	//TODO: DELETED
+                //result = PluginController.getInstance().searchOne(r.getURI().toString(),
+                //query , extrafields, r.getURI().toString(), this);
+                
+            	
+            	//System.out.println("Query: " + query);
+                //System.out.println("Plugin: " + r.getPluginName());
+                //System.out.println("Waiting for results");
+                resultArr.addAll(result.getArray());
+                try {
+                    this.wait(WAIT_TIME);
+                } catch (InterruptedException ex) {
+                    LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+                }
+            }
+            //System.out.println("Received the results + "+resultArr.size());
+            //System.out.println("Received the results + "+result.getArray());
+            return resultArr;*/
+        }
+        
+        public List<SearchResult> getResults()
+        {
+            //System.out.println("Received the results2 + "+resultArr.size());
+            //System.out.println("Received the results2 + "+result.getArray());
+            return this.resultArr;
+        }
+        
+        @Override
+        public void update(Observable o, Object o1) 
+        {
+            //System.out.println("Update + "+o);
+            if (o1==null)
+            {
+                synchronized(this)
+                {
+                    this.notifyAll();
+                }
+                return;
+            }
+            ArrayList tmp = ((ListObservableSearch) o1).getArray();
+            //System.out.println("Result_: " + tmp);
+            //System.out.println("Received a result_");
+            synchronized(this)
+            {
+                resultArr.addAll(tmp);
+                this.notifyAll();
+            }
+            //System.out.println("Received a result - done notification_");
+   
+        }
+    }
+    
+    @Override
+    public ArrayList<SearchResult> SearchIndexedMetaData(SearchResult searchResult) throws RemoteException {
+        
+        TagsStruct tags = TagsStruct.getInstance();
+        
+        ArrayList<String> extraFields = new ArrayList<>();
+        
+        for(TagValue tag : tags.getAllFields())
+        	extraFields.add(tag.getAlias());
+        
+        String query = "FileName:" + searchResult.getURI() + " AND FileHash:"+ searchResult.get("filehash");
+
+        
+        SearchDumper sdumper = new SearchDumper();
+        sdumper.search(searchResult, query, extraFields);
+        List<SearchResult> result = sdumper.getResults();
+        //System.out.println("Result + " +result);
+        if (result.size() > 0) {
+            
+            SearchResult r = (SearchResult) result.get(0);
+            for (String s:r.getExtraData().keySet())
+            {
+                if (s.contains("Sequence"))
+                {
+                    String [] fields = r.getExtraData().get(s).toString().split(" ");
+                    for (int i = 0 ; i<fields.length; i++)
+                    {
+                            extraFields.add(fields[i]);
+                    }
+                    
+                }
+            }
+            
+            sdumper = new SearchDumper();
+            sdumper.search(searchResult, query, extraFields);
+            result = sdumper.getResults();
+         
+        }
+        
+        return (ArrayList<SearchResult>) result;
+    }
+    
+    
+    
+
+    @Override
+    public long getSearchTime() throws RemoteException
+    {
+        return searchTime;
+    }
+
+    @Override
+    public void RegisterSignalBack(ISearchSignal signalBack) throws RemoteException
+    {
+        //System.out.println("Registring SignalBack");
+
+        //if(signalBack == null)
+        //    System.out.println("signalBack == null");
+        //else
+        //    System.out.println("signalBack != null");
+
+        searchSignal = signalBack;
+
+        //System.out.println("SignalBack Registered");
+    }
+
+    @Override
+    public FileObservable RequestP2PFile(SearchResult file) throws RemoteException
+    {
+        //TOSO: fix this
+       // return PluginController.getInstance().requestFile(file.getURI(), file.getURI(), file.getURI(), file.get("filehash"));
+        //PeerEngine.getInstance().requestFile(file.getAddress(), file.getFileName(), file.getFileHash());
+        return null;
+    }
+
+    /**
+     * Don't work with SearchResultP2P
+     * 
+     * @param file
+     * @return
+     * @throws RemoteException
+     */
+    @Override
+    public SimpleEntry<RemoteFile, Integer> downloadFile(SearchResult result) throws RemoteException
+    {
+        /*if (!PluginController.getInstance().isLocalPlugin(result.getPluginName()))
+        {
+            return null;
+        }*/
+        try
+        {
+            String path = result.getURI().toString().replace('\\', '/');
+
+            File file = new File(path);
+            InetAddress client = InetAddress.getByName(RemoteServer.getClientHost());
+
+            FileSender sender = new FileSender(file, client);
+
+            SimpleEntry<RemoteFile, Integer> entry = new SimpleEntry<RemoteFile, Integer>(new RemoteFile(file), sender.getListenerPort());
+
+            //DebugManager.getInstance().debug("Transfering file: " + entry.getKey().getName() + ", listening port: " + entry.getValue());
+
+            Thread tSender = sender;
+            tSender.start();
+
+            return entry;
+
+        } catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public List<NetworkMember> getPeerList() throws RemoteException
+    {
+    	//TODO: DELETED
+        //return PluginController.getInstance().getMembers();
+    	return null;
+    }
+
+    @Override
+    public ArrayList<SearchResult> getSearchResults() throws RemoteException
+    {
+        ArrayList<SearchResult> returnResultList = resultList;
+
+        resultList = null;
+
+        return returnResultList;
+    }
+
+    @Override
+    public ArrayList<SearchResult> getP2PSearchResults() throws RemoteException
+    {
+        ArrayList<SearchResult> returnResultList = P2PResultList;
+
+        P2PResultList = null;
+
+        return returnResultList;
+    }
+
+    @Override
+    public ArrayList<SearchResult> getExportSearchResults() throws RemoteException
+    {
+        ArrayList<SearchResult> returnResultList = exportList;
+
+        exportList = null;
+
+        return returnResultList;
+    }
+
+    @Override
+    public SearchResult getThumbnail(URI FileName, String FileHash) throws RemoteException
+    {
+        return searchHelper.searchThumbnail(FileName, FileHash);
+    }
+
+    @Override
+    public void getP2PThumbnail(URI FileName, String FileHash, String addr) throws RemoteException
+    {
+        searchHelper.searchP2PThumbnail(FileName, FileHash, addr);
+    }
+
+    @Override
+    public ArrayList<SearchResult> getPendingP2PThumnails() throws RemoteException
+    {
+        ArrayList<SearchResult> returnResultList = pendingP2PThumbnails;
+
+        pendingP2PThumbnails = null;
+
+        return returnResultList;
+    }
+
+    @Override
+    public HashMap<String, Integer> getTagList() throws RemoteException
+    {
+        return DictionaryAccess.getInstance().getTagList();
+    }
+
+    @Override
+    public HashMap<Integer, TagValue> getDIMFields() throws RemoteException
+    {
+    	Set<TagValue> fields = TagsStruct.getInstance().getDIMFields();
+    	HashMap<Integer, TagValue> map = new HashMap<>(fields.size());
+    	for(TagValue tag : fields)
+    		map.put(tag.getTagNumber(), tag);
+    	
+        return map;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/StartupServices.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/StartupServices.java
new file mode 100755
index 0000000..b3df256
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/StartupServices.java
@@ -0,0 +1,241 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.concurrent.Semaphore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IStartupServ;
+
+/**
+ * Controller of Startup Services Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class StartupServices implements IStartupServ {
+
+    private static Semaphore sem = new Semaphore(1, true);
+    private static StartupServices instance = null;
+
+    private ServerSettings settings;
+    
+    private boolean p2p;
+    private boolean storage;
+    private boolean qr;
+    private boolean web;
+    private boolean webservices;
+    private int storagePort;
+    private int webPort;
+    private int webservicesPort;
+    private int QRPort;
+    private int remoteGUIPort;
+    private String remoteGUIExtIP;
+
+    public static synchronized StartupServices getInstance() {
+        try {
+            sem.acquire();
+            if (instance == null) {
+                instance = new StartupServices();
+            }
+            sem.release();
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(StartupServices.class).error(ex.getMessage(), ex);
+        }
+
+        return instance;
+    }
+
+    private StartupServices() {
+        settings = ServerSettings.getInstance();
+                
+        loadSettings();
+    }
+
+    /**
+     * Load Settings from ServerSettings
+     */
+    public void loadSettings() {
+      //  p2p = settings.isP2P();
+        storage = settings.isStorage();
+        qr = settings.isQueryRetrive();
+        web = settings.getWeb().isWebServer();
+        webservices = settings.getWeb().isWebServices();
+
+        storagePort = settings.getStoragePort();
+        webPort = settings.getWeb().getServerPort();
+        webservicesPort = settings.getWeb().getServicePort();
+        QRPort = settings.getWlsPort();
+        
+        remoteGUIPort = settings.getRemoteGUIPort();
+        remoteGUIExtIP = settings.getRGUIExternalIP();
+    }
+
+    /**
+     * Save the settings related to Startup Services
+     *
+     * not write the settings in XML
+     */
+    public void saveSettings() {
+   //     settings.setP2P(p2p);
+        settings.setStorage(storage);
+        settings.setQueryRetrive(qr);
+        settings.getWeb().setWebServer(web);
+        settings.getWeb().setWebServices(webservices);
+
+        settings.setStoragePort(storagePort);
+        settings.getWeb().setServerPort(webPort);
+        settings.getWeb().setServicePort(webservicesPort);
+        settings.setWlsPort(QRPort);
+        settings.setRemoteGUIPort(remoteGUIPort);
+        settings.setRGUIExternalIP(remoteGUIExtIP);
+    }
+
+    /**
+     *
+     * @return  true - if there are unsaved settings ( != ServerSettings)
+     *          false - not
+     */
+    public boolean unsavedSettings() {
+        if (/*p2p != settings.isP2P() ||*/ storage != settings.isStorage()
+                || qr != settings.isQueryRetrive() || web != settings.getWeb().isWebServer()
+                || webservices != settings.getWeb().isWebServices() || storagePort != settings.getStoragePort()
+                || webPort != settings.getWeb().getServerPort() || webservicesPort != settings.getWeb().getServicePort()
+                || remoteGUIPort != settings.getRemoteGUIPort() || QRPort != settings.getWlsPort()
+                || (remoteGUIExtIP != null && !remoteGUIExtIP.equals(settings.getRGUIExternalIP()))) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void setP2P(boolean value) throws RemoteException {
+        p2p = value;
+    }
+
+    @Override
+    public boolean getP2P() throws RemoteException {
+        return p2p;
+    }
+
+    @Override
+    public void setDICOMStorage(boolean value) throws RemoteException {
+        storage = value;
+    }
+
+    @Override
+    public boolean getDICOMStorage() throws RemoteException {
+        return storage;
+    }
+
+    @Override
+    public void setDICOMStoragePort(int value) throws RemoteException {
+        storagePort = value;
+    }
+
+    @Override
+    public int getDICOMStoragePort() throws RemoteException {
+        return storagePort;
+    }
+
+    @Override
+    public void setDICOMQR(boolean value) throws RemoteException {
+        qr = value;
+    }
+
+    @Override
+    public boolean getDICOMQR() throws RemoteException {
+        return qr;
+    }
+
+    @Override
+    public void setWebServer(boolean value) throws RemoteException {
+        web = value;
+    }
+
+    @Override
+    public boolean getWebServer() throws RemoteException {
+        return web;
+    }
+
+    @Override
+    public void setWebServerPort(int value) throws RemoteException {
+        webPort = value;
+    }
+
+    @Override
+    public int getWebServerPort() throws RemoteException {
+        return webPort;
+    }
+
+    @Override
+    public void setWebServices(boolean value) throws RemoteException {
+        webservices = value;
+    }
+
+    @Override
+    public boolean getWebServices() throws RemoteException {
+        return webservices;
+    }
+
+    @Override
+    public void setWebServicesPort(int value) throws RemoteException {
+        webservicesPort = value;
+    }
+
+    @Override
+    public int getWebServicesPort() throws RemoteException {
+        return webservicesPort;
+    }
+
+    @Override
+    public void setRemoteGUIPort(int value) throws RemoteException {
+        remoteGUIPort = value;
+    }
+
+    @Override
+    public int getRemoteGUIPort() throws RemoteException {
+        return remoteGUIPort;
+    }
+
+    @Override
+    public void setDICOMQRPort(int value) throws RemoteException {
+        QRPort = value;
+    }
+
+    @Override
+    public int getDICOMQRPort() throws RemoteException {
+        return QRPort;
+    }
+
+    @Override
+    public void setRemoteGUIExtIP(String IP) throws RemoteException {
+        remoteGUIExtIP = IP;
+    }
+
+    @Override
+    public String getRemoteGUIExtIP() throws RemoteException {
+        return remoteGUIExtIP;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/TaskList.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/TaskList.java
new file mode 100755
index 0000000..e844b2b
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/TaskList.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
+import org.apache.commons.lang.NotImplementedException;
+
+import pt.ua.dicoogle.rGUI.interfaces.controllers.ITaskList;
+import pt.ua.dicoogle.rGUI.interfaces.signals.ITaskListSignal;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+ at Deprecated
+public class TaskList implements ITaskList
+{
+
+    private ITaskListSignal signalBack;
+    private static TaskList instance = null;
+
+    public static synchronized TaskList getInstance()
+    {
+
+        if (instance == null)
+        {
+            instance = new TaskList();
+        }
+        return instance;
+    }
+
+    public void resetSignalBack()
+    {
+        signalBack = null;
+    }
+
+    @Override
+    public void RegisterSignalBack(ITaskListSignal signalBack) throws RemoteException
+    {
+        this.signalBack = signalBack;
+    }
+
+    @Override
+    public ArrayList<String> getTaskList()  throws RemoteException
+    {
+
+        throw new NotImplementedException("Deprecated: RMI", null);
+    }
+
+
+    @Override
+    public void updatedTasks() throws RemoteException
+    {
+        if (signalBack!=null)
+            this.signalBack.sendTaskSignal(0);
+    }
+
+    @Override
+    public boolean isIndexing() throws RemoteException
+    {
+        throw new NotImplementedException("Deprecated: RMI", null);
+    }
+
+    @Override
+    public int getPercentCompleted() throws RemoteException
+    {
+        throw new NotImplementedException("Deprecated: RMI", null);
+
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/UsersManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/UsersManager.java
new file mode 100755
index 0000000..584f093
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/rGUI/server/controllers/UsersManager.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.rGUI.server.controllers;
+
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IUsersManager;
+import pt.ua.dicoogle.server.users.HashService;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UsersStruct;
+import pt.ua.dicoogle.server.users.UsersXML;
+
+/**
+ * Controller of Users Manager Settings
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class UsersManager implements IUsersManager {
+    private static UsersManager instance = null;
+
+    private UsersStruct users;
+
+    private boolean encryptUsersFile;
+
+    //flag to indicate when setting are unsaved
+    private boolean unsavedSettings;
+
+    public static synchronized UsersManager getInstance() {
+        if (instance == null) {
+            instance = new UsersManager();
+        }
+
+        return instance;
+    }
+
+    private UsersManager(){
+        users = UsersStruct.getInstance();
+
+        unsavedSettings = false;
+        encryptUsersFile = ServerSettings.getInstance().isEncryptUsersFile();
+    }
+
+    public void loadSettings(){
+        unsavedSettings = false;
+
+        UsersXML xml = new UsersXML();
+        xml.getXML();
+
+        encryptUsersFile = ServerSettings.getInstance().isEncryptUsersFile();
+    }
+    
+    /**
+     *
+     * @return  true - if there are unsaved settings
+     *          false - not
+     */
+    public boolean unsavedSettings(){
+        return unsavedSettings || (encryptUsersFile != ServerSettings.getInstance().isEncryptUsersFile());
+    }
+
+    /**
+     * Save the current Users configuration
+     *
+     *  write in XML
+     */
+    public void saveSettings(){
+        ServerSettings.getInstance().setEncryptUsersFile(encryptUsersFile);
+        
+        UsersXML xml = new UsersXML();
+        xml.printXML();
+
+        unsavedSettings = false;
+    }
+
+    @Override
+    public ArrayList<String> getUsernames() throws RemoteException {
+
+        Iterator<String> en = users.getUsernames().iterator();
+
+        ArrayList<String> list = new ArrayList<String>();
+
+        while(en.hasNext())
+            list.add(en.next());
+
+        list.trimToSize();
+
+        return list;
+    }
+
+    @Override
+    public boolean isAdmin(String username) throws RemoteException {
+        User user = users.getUser(username);
+
+        if(user != null && user.isAdmin())
+            return true;
+
+        return false;
+    }
+
+    /**
+     * Remove one user
+     *
+     * @param username
+     * @return  true if the user is removed
+     *          false if username doesn't exist
+     * @throws RemoteException
+     */
+    @Override
+    public boolean deleteUser(String username) throws RemoteException {
+        boolean temp = users.removeUser(username);
+
+        if (temp){
+            unsavedSettings = true;
+            Logs.getInstance().addServerLog("User " + username + " deleted");
+        }
+
+        return temp;
+    }
+
+    /**
+     * Adds one user to the user list
+     * 
+     * @param username
+     * @param passwordHash
+     * @param admin
+     * 
+     * @return  true if user is successfully addes to the list
+     *          false if the username already exists or username or password are invalid
+     * 
+     * @throws RemoteException
+     */
+    @Override
+    public boolean addUser(String username, String passwordHash, boolean admin) throws RemoteException {
+        if(username == null || username.equals("") || passwordHash == null || username.equals("") || passwordHash.equals(""))
+            return false;
+
+        String Hash = HashService.getSHA1Hash(username + admin + passwordHash);   //user Hash
+
+        User user = new User(username, Hash, admin);
+
+        boolean temp = users.addUser(user);
+
+        if(temp){
+            unsavedSettings = true;
+            Logs.getInstance().addServerLog("User " + username + " created");
+        }
+
+
+        return temp;
+    }
+
+    @Override
+    public boolean getEncryptUsersFile() throws RemoteException {
+        return encryptUsersFile;
+    }
+
+    @Override
+    public void setEncryptUsersFile(boolean value) throws RemoteException {
+        encryptUsersFile = value;
+    }
+
+    @Override
+    public boolean resetPassword(String username, String passwordHash) throws RemoteException {
+        if(username == null || username.equals("") || passwordHash == null || username.equals("") || passwordHash.equals(""))
+            return false;
+
+        User user = users.getUser(username);
+
+        if(user != null && user.resetPassword(passwordHash)){
+            unsavedSettings = true;
+
+            return true;
+        }
+
+        return false;
+    }
+
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/ControlServices.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/ControlServices.java
new file mode 100755
index 0000000..cfa5447
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/ControlServices.java
@@ -0,0 +1,280 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.slf4j.Logger;
+import pt.ua.dicoogle.server.queryretrieve.QueryRetrieve;
+
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IServices;
+import pt.ua.dicoogle.rGUI.server.controllers.Logs;
+import pt.ua.dicoogle.server.web.DicoogleWeb;
+import pt.ua.dicoogle.taskManager.TaskManager;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class ControlServices implements IServices
+{
+    private static final Logger logger = LoggerFactory.getLogger(ControlServices.class);
+    
+    private static ControlServices instance = null;
+    // Services vars
+    private RSIStorage storage = null;
+    private boolean webServicesRunning = false;
+    private boolean webServerRunning = false;
+    private QueryRetrieve retrieve = null;
+    
+    private DicoogleWeb webServices;
+    
+    private ControlServices()
+    {
+        TaskManager taskManager = new TaskManager(Integer.parseInt(System.getProperty("dicoogle.taskManager.nThreads", "4")));
+
+        startInicialServices();
+    }
+
+    public static synchronized ControlServices getInstance()
+    {
+//      sem.acquire();
+        if (instance == null)
+        {
+            instance = new ControlServices();
+        }
+//      sem.release();
+        return instance;
+    }
+
+
+    /* Strats the inicial services based on ServerSettings */
+    private void startInicialServices()
+    {
+        ServerSettings settings = ServerSettings.getInstance();
+
+        try
+        {
+          /*  if (settings.isP2P())
+            {
+                startP2P();
+            }*/
+
+            if (settings.isStorage())
+            {
+                startStorage();
+            }
+
+            if (settings.isQueryRetrive())
+            {
+                startQueryRetrieve();
+            }
+
+            if(settings.getWeb().isWebServer()){
+            	startWebServer();
+            }
+
+            if (settings.getWeb().isWebServices())
+            {
+                startWebServices();
+            }
+
+        } catch (Exception ex)
+        {
+            logger.error(ex.getMessage(), ex);
+        }
+    }
+
+    /* Stop all services that are running */
+    @Override
+    public boolean stopAllServices()
+    {
+        try
+        {
+        	//TODO: DELETED
+            //PluginController.getInstance().stopAll();
+           // stopP2P();
+            stopStorage();
+            stopQueryRetrieve();
+            stopWebServices();
+        } catch (Exception ex)
+        {
+            logger.error(ex.getMessage(), ex);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     *
+     * @return   0 - if everything is fine and the service was started
+     *          -1 - if the server's storage path is not defined
+     *          -2 - service is already running
+     * 
+     * @throws IOException
+     */
+    @Override
+    public int startStorage() throws IOException
+    {
+        if (storage == null)
+        {
+            ServerSettings settings = ServerSettings.getInstance();
+
+            SOPList list = SOPList.getInstance();
+            //list.setDefaultSettings();
+
+            int i;
+
+            List l = list.getKeys();
+            String[] keys = new String[l.size()];
+
+            for (i = 0; i < l.size(); i++)
+            {
+                keys[i] = (String) l.get(i);
+            }
+            storage = new RSIStorage(keys, list);
+            storage.start();
+
+            //DebugManager.getInstance().debug("Starting DICOM Storage SCP");
+            Logs.getInstance().addServerLog("Starting DICOM Storage SCP");
+
+            return 0;
+        }
+
+        return -2;
+    }
+
+    @Override
+    public void stopStorage()
+    {
+        if (storage != null)
+        {
+            storage.stop();
+            storage = null;
+            //DebugManager.getInstance().debug("Stopping DICOM Storage SCP");
+            Logs.getInstance().addServerLog("Stopping DICOM Storage SCP");
+        }
+    }
+
+    @Override
+    public boolean storageIsRunning()
+    {
+        return storage != null;
+    }
+
+    @Override
+    public void startQueryRetrieve()
+    {
+        if (retrieve == null)
+        {
+            retrieve = new QueryRetrieve();
+            retrieve.startListening();
+            //DebugManager.getInstance().debug("Starting DICOM QueryRetrive");
+            Logs.getInstance().addServerLog("Starting DICOM QueryRetrive");
+        }
+    }
+
+    @Override
+    public void stopQueryRetrieve()
+    {
+        if (retrieve != null)
+        {
+            retrieve.stopListening();
+            retrieve = null;
+            //DebugManager.getInstance().debug("Stopping DICOM QueryRetrive");
+            Logs.getInstance().addServerLog("Stopping DICOM QueryRetrive");
+        }
+    }
+
+    @Override
+    public boolean queryRetrieveIsRunning()
+    {
+        return retrieve != null;
+    }
+
+    @Override
+    public boolean webServerIsRunning()
+    {
+        return webServerRunning;
+    }
+
+    @Override
+    @Deprecated
+    public void startWebServices()
+    {
+    }
+
+    @Override
+    @Deprecated
+    public void stopWebServices()
+    {
+    }
+
+    @Override
+    public boolean webServicesIsRunning()
+    {
+        return webServicesRunning;
+    }
+    
+    //TODO: Review those below!
+    @Override
+    public void startWebServer(){
+        logger.info("Starting WebServer");
+
+        try {
+            if (webServices == null) {
+                webServices = new DicoogleWeb(ServerSettings.getInstance().getWeb().getServerPort());
+                webServerRunning = true;
+                webServicesRunning = true;
+                logger.info("Starting Dicoogle Web");
+            }
+        } catch (Exception ex) {
+            logger.error("Failed to launch the web server", ex);
+        }
+        
+    }
+
+    @Override
+    public void stopWebServer(){
+        logger.info("Stopping Web Server");
+        
+        if(webServices != null){
+            try { 
+                webServicesRunning = false;
+                webServerRunning = false;
+                
+                webServices.stop();
+                
+                webServices = null;
+            } catch (Exception ex) {
+                logger.error(ex.getMessage(), ex);
+            }
+        }
+        logger.info("Stopping Dicoogle Web");
+    }
+    
+    public DicoogleWeb getWebServicePlatform(){
+    	return webServices;
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomDirCreator.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomDirCreator.java
new file mode 100755
index 0000000..fa84f3f
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomDirCreator.java
@@ -0,0 +1,181 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import java.io.File;
+import java.io.IOException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.io.DicomInputStream;
+import org.dcm4che2.io.StopTagInputHandler;
+import org.dcm4che2.media.ApplicationProfile;
+import org.dcm4che2.media.BasicApplicationProfile;
+import org.dcm4che2.media.DicomDirReader;
+import org.dcm4che2.media.DicomDirWriter;
+import org.dcm4che2.media.FileSetInformation;
+
+
+
+/**
+ * Creates, updates and rebuilds DICOMDIR Files.
+ * @author Marco
+ */
+public class DicomDirCreator {
+    
+    private String Path;
+    private String id;
+    private DicomDirReader dicomdir;
+    private FileSetInformation fsinfo = null;
+    private ApplicationProfile ap = new BasicApplicationProfile();
+    
+    /**
+     * Creates a new DicomDirCreator object.
+     * If the DICOMDIR file doesn't exist it creates a new one,
+     * otherwise it will open the existing one.
+     * @param P Path to where the DICOMDIR file is going to be created.
+     * @param I FilesetID
+     */
+    public DicomDirCreator(String P, String I)
+    {
+        Path = P;
+        id = I;
+        File file = new File(Path+File.separator+"DICOMDIR");
+        if (!file.exists())
+        {           
+            try {
+                fsinfo = new FileSetInformation();
+                fsinfo.init();                
+                if(id != null)
+                {
+                    if(!id.isEmpty())
+                    {
+                        fsinfo.setFileSetID(id);
+                    }
+                }
+                dicomdir = new DicomDirWriter(file, fsinfo);
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+            }
+        }
+        else
+        {
+            try {
+                dicomdir = new DicomDirWriter(file);
+                fsinfo = dicomdir.getFileSetInformation();
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+            }
+        }
+     }
+    
+    /**
+     * Updates the DICOMDIR file with a new entry
+     * @param f File to be added to DICOMDIR
+     */
+    public synchronized void updateDicomDir(File f)
+    {
+        // Severe dcm4che bug fix; it had a problem building dicom directories with files / folders beginning with a dot
+        if (f != null && !f.getName().startsWith("."))
+        {
+            if(f.isDirectory())
+            {
+                File[] fs = f.listFiles();
+                
+                for (int i = 0; i < fs.length; i++)
+                    updateDicomDir(fs[i]);
+               
+                return;
+            }
+            
+            // Only dcm files will be listed in the dicom directory
+            if (f.getName().endsWith(".dcm"))
+            {
+                DicomInputStream dis = null;
+                try {
+                    dis = new DicomInputStream(f);
+                    dis.setHandler(new StopTagInputHandler(Tag.PixelData));
+                    DicomObject d = dis.readDicomObject();
+                    DicomObject p_record = ap.makePatientDirectoryRecord(d);
+                    DicomObject sty_record = ap.makeStudyDirectoryRecord(d);
+                    DicomObject s_record = ap.makeSeriesDirectoryRecord(d);
+                    DicomObject i_record = ap.makeInstanceDirectoryRecord(d, dicomdir.toFileID(f));
+                    DicomObject record = ((DicomDirWriter) dicomdir).addPatientRecord(p_record);
+                    record = ((DicomDirWriter) dicomdir).addStudyRecord(record, sty_record);
+                    record = ((DicomDirWriter) dicomdir).addSeriesRecord(record, s_record);
+                    ((DicomDirWriter) dicomdir).addChildRecord(record, i_record);
+                    ((DicomDirWriter) dicomdir).commit();
+
+                } catch (IOException ex) {
+                    LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+                } finally {
+                    try {
+                        dis.close();
+                    } catch (IOException ex) {
+                        LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+                    }
+                }
+            }
+        }
+   }
+    
+     /**
+     * Rebuilds the DICOMDIR file, by rescanning the storage path.
+     * To avoid conflicts should only be called when the server is not running.
+     */
+    public synchronized void dicomdir_rebuild()
+    {
+        try {
+            dicomdir.close();
+            File file = new File(Path + File.separator + "DICOMDIR");
+            file.delete();
+            File f = new File(Path);            
+            fsinfo = new FileSetInformation();
+                fsinfo.init();                
+                if(id != null)
+                {
+                    if(!id.isEmpty())
+                    {
+                        fsinfo.setFileSetID(id);
+                    }
+                }
+                dicomdir = new DicomDirWriter(file, fsinfo);                
+                updateDicomDir(f);                                 
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+        }
+    }
+    
+    /**
+     * Closes the DICOMDIR Reader/Writer     
+     */
+    public void dicomdir_close()
+    {
+        try {
+            dicomdir.close();
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(DicomDirCreator.class).error(ex.getMessage(), ex);
+        }
+    }
+    
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomNetwork.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomNetwork.java
new file mode 100755
index 0000000..e5a708a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/DicomNetwork.java
@@ -0,0 +1,250 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+/*
+ * Dicom Network is a singletone class to handler the services
+ * Each Device have a Application Entity and a Device can have multiple
+ * connections. Hence for an Application Entity we have multiple connections 
+ * associated too. 
+ * 
+ * Dicoogle is available to keep some DICOM services up,
+ * but services need to be handled and forward to correct entity 
+ * 
+ * 
+ */
+
+package pt.ua.dicoogle.server;
+
+
+import pt.ua.dicoogle.server.callbacks.LogEvent;
+import pt.ua.dicoogle.server.callbacks.LogEventAfter;
+import pt.ua.dicoogle.server.callbacks.LogEventBefore;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public abstract class DicomNetwork
+{    
+    
+
+    private NetworkApplicationEntity remoteAE = new NetworkApplicationEntity();
+    private NetworkConnection remoteConn = new NetworkConnection();
+    private Device device = null ;
+    private NetworkApplicationEntity localAE = new NetworkApplicationEntity();
+    private NetworkConnection localConn = new NetworkConnection();
+
+
+    // AETitle of Service
+    private String AETitle = null ;
+
+
+    /** Event Interface Calls */ 
+    LogEvent eventService = null ;
+    LogEventBefore eventBefore = null ;
+    LogEventAfter eventAfter = null ;
+
+    private String deviceName = null ;
+    
+    public DicomNetwork(String DeviceName)
+    {
+        // Starts Device
+        device = new Device(DeviceName);
+        this.deviceName = DeviceName; 
+    }
+
+
+
+    /**
+     * Connect to the service after happen
+     * For example in the case of c-move it will happen after send all images
+     *
+     * @param e An class that implement methods to be call
+     * @return a boolean to know if event will be triggered or not
+     */
+    public boolean connectAfter(LogEventAfter e)
+    {
+        boolean result = false ;
+        if (e != null && e instanceof LogEventAfter  )
+        {
+            result = true ;
+        }
+        this.eventAfter = e ;
+        return result ; 
+    }
+
+
+    /**
+     * Connect to the service before happen
+     * For example in the case of c-move it will happen before send images
+     *
+     * @param e An class that implement methods to be call
+     * @return a boolean to know if event will be triggered or not
+     */
+    public boolean connectBefore(LogEventBefore e)
+    {
+        boolean result = false ;
+        if (e != null && e instanceof LogEventBefore  )
+        {
+            result = true ;
+        }
+        this.eventBefore = e ;
+        return result ;
+    }
+
+    /**
+     * When a service is started or stopped it will be called after service
+     * start/stop
+     * @param e the class that have necessary callbacks implemented
+     * @return
+     */
+
+    public boolean connectServices(LogEvent e)
+    {
+        boolean result = false ;
+        if (e != null && e instanceof LogEvent )
+        {
+            result = true ;
+        }
+        this.eventService = e ;
+        return result ;
+    }
+
+
+
+
+    public boolean startListening()
+    {
+        boolean result = false;
+
+        result = doStartService();
+        if (this.eventService!=null)
+            this.eventService.startService(this.deviceName +  " was started " +
+                    "QueryRetrieve");
+        return result ; 
+          
+    }
+
+
+    public boolean stopListening()
+    {
+        boolean result = false;
+
+        result = doStopService();
+        if (this.eventService!=null)
+            this.eventService.stopService(this.deviceName +  " was stoppped" +
+                    " QueryRetrieve");
+        return result ;
+    }
+
+    public abstract boolean doStartService();
+    public abstract boolean doStopService();
+    
+
+
+    /**
+     * @return the remoteAE
+     */
+    public NetworkApplicationEntity getRemoteAE() {
+        return remoteAE;
+    }
+
+    /**
+     * @param remoteAE the remoteAE to set
+     */
+    public void setRemoteAE(NetworkApplicationEntity remoteAE) {
+        this.remoteAE = remoteAE;
+    }
+
+    /**
+     * @return the remoteConn
+     */
+    public NetworkConnection getRemoteConn() {
+        return remoteConn;
+    }
+
+    /**
+     * @param remoteConn the remoteConn to set
+     */
+    public void setRemoteConn(NetworkConnection remoteConn) {
+        this.remoteConn = remoteConn;
+    }
+
+    /**
+     * @return the device
+     */
+    public Device getDevice() {
+        return device;
+    }
+
+    /**
+     * @param device the device to set
+     */
+    public void setDevice(Device device) {
+        this.device = device;
+    }
+
+    /**
+     * @return the localAE
+     */
+    public NetworkApplicationEntity getLocalAE() {
+        return localAE;
+    }
+
+    /**
+     * @param localAE the localAE to set
+     */
+    public void setLocalAE(NetworkApplicationEntity localAE) {
+        this.localAE = localAE;
+    }
+
+    /**
+     * @return the localConn
+     */
+    public NetworkConnection getLocalConn() {
+        return localConn;
+    }
+
+    /**
+     * @param localConn the localConn to set
+     */
+    public void setLocalConn(NetworkConnection localConn) {
+        this.localConn = localConn;
+    }
+
+    /**
+     * @return the AETitle
+     */
+    public String getAETitle() {
+        return AETitle;
+    }
+
+    /**
+     * @param AETitle the AETitle to set
+     */
+    public void setAETitle(String AETitle) {
+        this.AETitle = AETitle;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/FileWatcher.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/FileWatcher.java
new file mode 100755
index 0000000..0d07fc1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/FileWatcher.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+/**
+ * Keeps track of modifications on a file
+ * @author Filipe Freitas
+ */
+import java.util.*;
+import java.io.*;
+
+public abstract class FileWatcher extends TimerTask {
+  private long timeStamp;
+  private File file;
+
+  public FileWatcher( File file )
+  {
+    this.file = file;
+    this.timeStamp = file.lastModified();    
+  }
+
+    @Override
+  public final void run()
+  { 
+    /* STUPID WINDOWS HACK
+     * 
+     * windows does NOT update the modified time
+     * of a file until it is closed (DOS Legacy code)
+     * 
+     */
+    
+    if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1)
+    {
+        onChange(file);
+    }
+    else
+    {
+        long localtimeStamp = file.lastModified();    
+        if( this.timeStamp != localtimeStamp ) 
+        {
+            this.timeStamp = localtimeStamp;
+            onChange(file);
+        }
+    }
+  }
+
+  protected abstract void onChange( File file );
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/LegacyRestletApplication.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/LegacyRestletApplication.java
new file mode 100644
index 0000000..ae298dd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/LegacyRestletApplication.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import org.slf4j.LoggerFactory;
+import org.restlet.Application;
+import org.restlet.Restlet;
+import org.restlet.routing.Router;
+import pt.ua.dicoogle.server.web.rest.ExamTimeResource;
+import pt.ua.dicoogle.server.web.rest.ForceIndexing;
+import pt.ua.dicoogle.server.web.rest.RestDcmImageResource;
+import pt.ua.dicoogle.server.web.rest.RestDimResource;
+import pt.ua.dicoogle.server.web.rest.RestDumpResource;
+import pt.ua.dicoogle.server.web.rest.RestFileResource;
+import pt.ua.dicoogle.server.web.rest.RestTagsResource;
+import pt.ua.dicoogle.server.web.rest.RestWADOResource;
+
+/** A Restlet Application for aggregating legacy web services.
+ *
+ * @author psytek
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class LegacyRestletApplication extends Application {
+
+    private Router internalRouter;
+    
+    public LegacyRestletApplication() {
+        super();
+    }
+    
+    /**
+     * Creates a root Restlet that will receive all incoming calls.
+     * @return a Restlet for the root 
+     */
+    @Override
+    public synchronized Restlet createInboundRoot() {
+        // Create a router Restlet that routes each call to a
+        // new instance of our resources
+        this.internalRouter = new Router(getContext());
+
+        // Define routing to resources
+        this.internalRouter.setDefaultMatchingQuery(false);
+        //internalRouter.attach("/test/{something}", TestResource.class);
+        internalRouter.attach("/dim", RestDimResource.class);//search resource
+        internalRouter.attach("/file", RestFileResource.class);//file download resource
+        internalRouter.attach("/dump", RestDumpResource.class);//dump resource
+        internalRouter.attach("/tags", RestTagsResource.class);//list of avalilable tags resource
+        //router.attach("/image", RestImageResource.class);//jpg image resource
+        //router.attach("/enumField", RestEnumField.class);
+        //router.attach("/countResuls", RestCountQueryResults.class);
+        internalRouter.attach("/wado", RestWADOResource.class);
+        internalRouter.attach("/img", RestDcmImageResource.class);
+        internalRouter.attach("/examTime", ExamTimeResource.class);
+        
+        //Advanced Dicoogle Features
+        internalRouter.attach("/doIndex", ForceIndexing.class);
+
+//        internalRouter.attachDefault(ExtResource.class);
+                
+        LoggerFactory.getLogger(LegacyRestletApplication.class).debug("Legacy service routes: {}",
+                internalRouter.getRoutes());
+        return internalRouter;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/PluginRestletApplication.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/PluginRestletApplication.java
new file mode 100755
index 0000000..0281850
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/PluginRestletApplication.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.LoggerFactory;
+import org.restlet.Application;
+import org.restlet.Restlet;
+import org.restlet.resource.ServerResource;
+import org.restlet.routing.Router;
+
+/** A Restlet Application for aggregating web services from plugins
+ *
+ * @author psytek
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class PluginRestletApplication extends Application {
+
+    private static final List<ServerResource> pluginServices = new ArrayList<>();
+    
+    private Router internalRouter;
+    
+    public PluginRestletApplication() {
+        super();
+    }
+    
+    /**
+     * Creates a root Restlet that will receive all incoming calls.
+     * @return a Restlet for the root 
+     */
+    @Override
+    public synchronized Restlet createInboundRoot() {
+        // Create a router Restlet that routes each call to a
+        // new instance of our resources
+        this.internalRouter = new Router(getContext());
+        // Defines routing to resources
+        this.internalRouter.setDefaultMatchingQuery(false);
+        
+        //lets add plugin registred services
+        //this is still a little brittle... :(
+        for(ServerResource resource : pluginServices) {
+            LoggerFactory.getLogger(PluginRestletApplication.class).debug("Inbound: {}", resource);
+            internalRouter.attach("/" + resource.toString(), resource.getClass());
+        }
+        
+        LoggerFactory.getLogger(PluginRestletApplication.class).debug("Installed plugin restlets: {}",
+                pluginServices);
+        return internalRouter;
+    }
+    
+    protected void loadPlugins() {
+    }
+    
+    public static void attachRestPlugin(ServerResource resource){
+        pluginServices.add(resource);
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/RSIStorage.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/RSIStorage.java
new file mode 100755
index 0000000..989cc38
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/RSIStorage.java
@@ -0,0 +1,517 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import pt.ua.dicoogle.core.ServerSettings;
+
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.*;
+
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.UID;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.DicomServiceException;
+
+///import org.dcm4che2.net.Executor;
+/** dcm4che doesn't support Executor anymore, so now import from java.util */ 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+import org.dcm4che2.net.NewThreadExecutor;
+import org.dcm4che2.net.PDVInputStream;
+import org.dcm4che2.net.Status;
+import org.dcm4che2.net.TransferCapability;
+import org.dcm4che2.net.service.StorageService;
+import org.dcm4che2.net.service.VerificationService;
+
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.IndexerInterface;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+
+
+/**
+ * DICOM Storage Service is provided by this class
+ * @author Marco Pereira
+ */
+
+public class RSIStorage extends StorageService
+{
+    
+    private SOPList list;
+    private ServerSettings settings;
+        
+    private Executor executor = new NewThreadExecutor("RSIStorage");
+    private Device device = new Device("RSIStorage");
+    private NetworkApplicationEntity nae = new NetworkApplicationEntity();
+    private NetworkConnection nc = new NetworkConnection();
+    
+    private String path;
+    private DicomDirCreator dirc;
+    
+    private int fileBufferSize = 256;
+    private int threadPoolSize = 10;
+    
+    private ExecutorService pool = Executors.newFixedThreadPool(threadPoolSize);
+    
+    private boolean gzip = ServerSettings.getInstance().isGzipStorage();;
+
+    private Set<String> alternativeAETs = new HashSet<>();
+    private Set<String> priorityAETs = new HashSet<>();
+
+    // Changed to support priority queue.
+    private BlockingQueue<ImageElement> queue = new PriorityBlockingQueue<ImageElement>();
+    private NetworkApplicationEntity[] naeArr = null;
+    
+    /**
+     * 
+     * @param Services List of supported SOP Classes
+     * @param l list of Supported SOPClasses with supported Transfer Syntax
+     * @param s Server Settings for this execution of the storage service
+     */
+    
+    public RSIStorage(String [] Services, SOPList l)
+    {
+        //just because the call to super must be the first instruction
+        super(Services); 
+        
+            //our configuration format
+            list = l;
+            settings = ServerSettings.getInstance();
+
+            // Added default alternative AETitle.
+            alternativeAETs.add(ServerSettings.getInstance().getNodeName());
+
+            path = settings.getPath();
+            if (path == null) {
+                path = "/dev/null";
+            }
+
+            this.priorityAETs = settings.getPriorityAETitles();
+            LoggerFactory.getLogger(RSIStorage.class).debug("Priority C-STORE: " + this.priorityAETs);
+
+            device.setNetworkApplicationEntity(nae);
+
+            device.setNetworkConnection(nc);
+            nae.setNetworkConnection(nc);
+
+            //we accept assoociations, this is a server
+            nae.setAssociationAcceptor(true);
+            //we support the VerificationServiceSOP
+            nae.register(new VerificationService());
+            //and the StorageServiceSOP
+            nae.register(this);
+
+            nae.setAETitle(settings.getAE());
+
+
+            nc.setPort(settings.getStoragePort());
+            
+            
+            this.nae.setInstalled(true);
+            this.nae.setAssociationAcceptor(true);
+            this.nae.setAssociationInitiator(false);
+            
+            
+            ServerSettings s  = ServerSettings.getInstance();
+            this.nae.setDimseRspTimeout(60000*300);
+            this.nae.setIdleTimeout(60000*300);
+            this.nae.setMaxPDULengthReceive(s.getMaxPDULengthReceive()+1000);
+            this.nae.setMaxPDULengthSend(s.getMaxPDULenghtSend()+1000);
+            this.nae.setRetrieveRspTimeout(60000*300);
+
+
+            // Added alternative AETitles.
+
+            naeArr = new NetworkApplicationEntity[alternativeAETs.size()+1];
+            // Just adding the first AETitle
+            naeArr[0] = nae;
+            
+            int k = 1 ; 
+            
+            for (String alternativeAET: alternativeAETs)
+            {
+                NetworkApplicationEntity nae2 = new NetworkApplicationEntity();
+                nae2.setNetworkConnection(nc);
+                nae2.setDimseRspTimeout(60000*300);
+                nae2.setIdleTimeout(60000*300);
+                nae2.setMaxPDULengthReceive(s.getMaxPDULengthReceive()+1000);
+                nae2.setMaxPDULengthSend(s.getMaxPDULenghtSend()+1000);
+                nae2.setRetrieveRspTimeout(60000*300);
+                //we accept assoociations, this is a server
+                nae2.setAssociationAcceptor(true);
+                //we support the VerificationServiceSOP
+                nae2.register(new VerificationService());
+                //and the StorageServiceSOP
+                nae2.register(this);
+                nae2.setAETitle(alternativeAET);
+                ServerSettings settings = ServerSettings.getInstance();
+                String[] array = settings.getCAET();
+
+                if (array != null)
+                {
+                    nae2.setPreferredCallingAETitle(settings.getCAET());
+                }
+                naeArr[k] = nae2;
+                k++;
+                
+            }
+
+            // Just set the Network Application Entity array - which accepts a set of AEs.
+            device.setNetworkApplicationEntity(naeArr);
+
+            
+
+            initTS(Services);
+    }
+    /**
+     *  Sets the tranfer capability for this execution of the storage service
+     *  @param Services Services to be supported
+     */
+    private void initTS(String [] Services)
+    {
+        int count = list.getAccepted();
+        //System.out.println(count);
+        TransferCapability[] tc = new TransferCapability[count + 1];
+        String [] Verification = {UID.ImplicitVRLittleEndian, UID.ExplicitVRLittleEndian, UID.ExplicitVRBigEndian};
+        String [] TS;
+        TransfersStorage local;        
+
+        tc[0] = new TransferCapability(UID.VerificationSOPClass, Verification, TransferCapability.SCP);
+        int j = 0;
+        for (int i = 0; i < Services.length; i++)
+        {
+            count = 0;
+            local = list.getTS(Services[i]);  
+            if (local.getAccepted())
+            {
+                TS = local.getVerboseTS();
+                if(TS != null)
+                {                
+
+                    tc[j+1] = new TransferCapability(Services[i], TS, TransferCapability.SCP);
+                    j++;
+                }                        
+            }
+        }
+        
+        // Setting the TS in all NetworkApplicationEntitys 
+        for (int i = 0 ; i<naeArr.length;i++)
+        {
+
+            naeArr[i].setTransferCapability(tc);
+        }
+        nae.setTransferCapability(tc);
+    }
+      
+    @Override
+    /**
+     * Called when a C-Store Request has been accepted
+     * Parameters defined by dcm4che2
+     */
+    public void cstore(final Association as, final int pcid, DicomObject rq, PDVInputStream dataStream, String tsuid) throws DicomServiceException, IOException
+    {
+        //DebugManager.getInstance().debug(":: Verify Permited AETs @??C-Store Request ");
+
+        boolean permited = false;
+
+        if(ServerSettings.getInstance().getPermitAllAETitles()){
+            permited = true;
+        }
+        else {
+            String permitedAETs[] = ServerSettings.getInstance().getCAET();
+
+            for (int i = 0; i < permitedAETs.length; i++) {
+                if (permitedAETs[i].equals(as.getCallingAET())) {
+                    permited = true;
+                    break;
+                }
+            }
+        }
+
+        if (!permited) {
+            //DebugManager.getInstance().debug("Client association NOT permited: " + as.getCallingAET() + "!");
+            System.err.println("Client association NOT permited: " + as.getCallingAET() + "!");
+            as.abort();
+            
+            return;
+        } else {
+            //DebugManager.getInstance().debug("Client association permited: " + as.getCallingAET() + "!");
+            System.err.println("Client association permited: " + as.getCallingAET() + "!");
+        }
+
+        final DicomObject rsp = CommandUtils.mkRSP(rq, CommandUtils.SUCCESS);
+        onCStoreRQ(as, pcid, rq, dataStream, tsuid, rsp);
+        as.writeDimseRSP(pcid, rsp);       
+        //onCStoreRSP(as, pcid, rq, dataStream, tsuid, rsp);
+    }
+    
+    @Override
+    /**
+     * Actually do the job of saving received file on disk
+     * on this server with extras such as Lucene indexing
+     * and DICOMDIR update
+     */
+    protected void onCStoreRQ(Association as, int pcid, DicomObject rq, PDVInputStream dataStream, String tsuid, DicomObject rsp) throws IOException, DicomServiceException 
+    {  
+        try
+        {
+
+            String cuid = rq.getString(Tag.AffectedSOPClassUID);
+            String iuid = rq.getString(Tag.AffectedSOPInstanceUID);
+
+            DicomObject d = dataStream.readDataset();
+            
+            d.initFileMetaInformation(cuid, iuid, tsuid);
+            
+            Iterable <StorageInterface> plugins = PluginController.getInstance().getStoragePlugins(true);
+
+            URI uri = null;
+            for (StorageInterface storage : plugins)
+            {
+                uri = storage.store(d);
+                if(uri != null) {
+                    // queue to index
+                    ImageElement element = new ImageElement();
+                    element.setCallingAET(as.getCallingAET());
+                    element.setUri(uri);
+                    queue.add(element);
+                }
+            }
+
+        } catch (IOException e) {
+           throw new DicomServiceException(rq, Status.ProcessingFailure, e.getMessage());          
+         }
+    }
+
+    /**
+     * ImageElement is a entry of a C-STORE. For Each C-STORE RQ
+     * an ImageElement is created and are put in the queue to index.
+     *
+     * This only happens after the store in Storage Plugins.
+     *
+     * @param <E>
+     */
+    class ImageElement<E extends Comparable<? super E>>
+            implements Comparable<ImageElement<E>>{
+        private URI uri;
+        private String callingAET;
+
+        public URI getUri() {
+            return uri;
+        }
+
+        public void setUri(URI uri) {
+            this.uri = uri;
+        }
+
+        public String getCallingAET() {
+            return callingAET;
+        }
+
+        public void setCallingAET(String callingAET) {
+            this.callingAET = callingAET;
+        }
+
+        @Override
+        public int compareTo(ImageElement<E> o1) {
+            if (o1.getCallingAET().equals(this.getCallingAET()))
+                return 0 ;
+            else if (settings.getPriorityAETitles().contains(this.getCallingAET()))
+                return -1;
+            else return 1;
+        }
+    }
+
+    
+    class Indexer extends Thread
+    {
+        public Collection<IndexerInterface> plugins;
+        
+        public void run()
+        {
+            while (true)
+            {
+                try 
+                {
+                    // Fetch an element by the queue taking into account the priorities.
+                    ImageElement element = queue.take();
+                    URI exam = element.getUri();
+                    if(exam != null)
+                    {
+                        List <Report> reports = PluginController.getInstance().indexBlocking(exam);
+                    }
+                } catch (InterruptedException ex) {
+                    LoggerFactory.getLogger(RSIStorage.class).error(ex.getMessage(), ex);
+                }
+                 
+            }
+            
+        }
+    }
+    
+    
+    private String getFullPath(DicomObject d)
+    {
+    
+        return getDirectory(d) + File.separator + getBaseName(d);
+    
+    }
+    
+    
+    private String getFullPathCache(String dir, DicomObject d)
+    {    
+        return dir + File.separator + getBaseName(d);
+ 
+    }
+    
+    
+    
+    private String getBaseName(DicomObject d)
+    {
+        String result = "UNKNOWN.dcm";
+        String sopInstanceUID = d.getString(Tag.SOPInstanceUID);
+        return sopInstanceUID+".dcm";
+    }
+    
+    
+    private String getDirectory(DicomObject d)
+    {
+    
+        String result = "UN";
+        
+        String institutionName = d.getString(Tag.InstitutionName);
+        String modality = d.getString(Tag.Modality);
+        String studyDate = d.getString(Tag.StudyDate);
+        String accessionNumber = d.getString(Tag.AccessionNumber);
+        String studyInstanceUID = d.getString(Tag.StudyInstanceUID);
+        String patientName = d.getString(Tag.PatientName);
+        
+        if (institutionName==null || institutionName.equals(""))
+        {
+            institutionName = "UN_IN";
+        }
+        institutionName = institutionName.trim();
+        institutionName = institutionName.replace(" ", "");
+        institutionName = institutionName.replace(".", "");
+        institutionName = institutionName.replace("&", "");
+
+        
+        if (modality == null || modality.equals(""))
+        {
+            modality = "UN_MODALITY";
+        }
+        
+        if (studyDate == null || studyDate.equals(""))
+        {
+            studyDate = "UN_DATE";
+        }
+        else
+        {
+            try
+            {
+                String year = studyDate.substring(0, 4);
+                String month =  studyDate.substring(4, 6);
+                String day =  studyDate.substring(6, 8);
+                
+                studyDate = year + File.separator + month + File.separator + day;
+                
+            }
+            catch(Exception e)
+            {
+                e.printStackTrace();
+                studyDate = "UN_DATE";
+            }
+        }
+        
+        if (accessionNumber == null || accessionNumber.equals(""))
+        {
+            patientName = patientName.trim();
+            patientName = patientName.replace(" ", "");
+            patientName = patientName.replace(".", "");
+            patientName = patientName.replace("&", "");
+            
+            if (patientName == null || patientName.equals(""))
+            {
+                if (studyInstanceUID == null || studyInstanceUID.equals(""))
+                {
+                    accessionNumber = "UN_ACC";
+                }
+                else
+                {
+                    accessionNumber = studyInstanceUID;
+                }
+            }
+            else
+            {
+                accessionNumber = patientName;
+                
+            }
+            
+        }
+        
+        result = path+File.separator+institutionName+File.separator+modality+File.separator+studyDate+File.separator+accessionNumber;
+        
+        return result;
+        
+    }
+    private Indexer indexer = new Indexer();
+    /*
+     * Start the Storage Service 
+     * @throws java.io.IOException
+     */
+    public void start() throws IOException
+    {       
+        //dirc = new DicomDirCreator(path, "Dicoogle");
+        pool = Executors.newFixedThreadPool(threadPoolSize);
+        device.startListening(executor); 
+        indexer.start();
+        
+
+    } 
+    
+    /**
+     * Stop the storage service 
+     */
+    public void stop()
+    {
+        this.pool.shutdown();
+        try {
+            pool.awaitTermination(6, TimeUnit.DAYS);
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(RSIStorage.class).error(ex.getMessage(), ex);
+        }
+        device.stopListening();
+        
+        //dirc.dicomdir_close();
+    }   
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/SOPList.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/SOPList.java
new file mode 100755
index 0000000..c6f6630
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/SOPList.java
@@ -0,0 +1,372 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import org.dcm4che2.data.UID;
+
+import pt.ua.dicoogle.server.web.management.Dicoogle.SOPClassSettings;
+
+/**
+ * Support class for keeping SOPClass/TransferSyntax association
+ * @author Marco Pereira
+ */
+
+public class SOPList {
+
+    private static SOPList instance = null;
+    private static Logger logger = LoggerFactory.getLogger(SOPList.class);
+
+    private Hashtable<String, TransfersStorage> table;    
+    
+    private String [] SOP = {
+        UID.BasicStudyContentNotificationSOPClassRetired,
+        UID.StoredPrintStorageSOPClassRetired,
+        UID.HardcopyGrayscaleImageStorageSOPClassRetired,
+        UID.HardcopyColorImageStorageSOPClassRetired,
+        UID.ComputedRadiographyImageStorage,
+        UID.DigitalXRayImageStorageForPresentation,
+        UID.DigitalXRayImageStorageForProcessing,
+        UID.DigitalMammographyXRayImageStorageForPresentation,
+        //UID.DigitalMammographyXRayImageStorageForProcessing,
+        UID.DigitalIntraOralXRayImageStorageForPresentation,
+        UID.DigitalIntraOralXRayImageStorageForProcessing,
+        UID.StandaloneModalityLUTStorageRetired,
+        UID.EncapsulatedPDFStorage,
+        UID.StandaloneVOILUTStorageRetired,
+        UID.GrayscaleSoftcopyPresentationStateStorageSOPClass,
+        UID.ColorSoftcopyPresentationStateStorageSOPClass,
+        UID.PseudoColorSoftcopyPresentationStateStorageSOPClass,
+        UID.BlendingSoftcopyPresentationStateStorageSOPClass,
+        UID.XRayAngiographicImageStorage,
+        UID.EnhancedXAImageStorage,
+        UID.XRayRadiofluoroscopicImageStorage,
+        UID.EnhancedXRFImageStorage,
+        UID.XRayAngiographicBiPlaneImageStorageRetired,
+        UID.PositronEmissionTomographyImageStorage,
+        UID.StandalonePETCurveStorageRetired,
+        UID.CTImageStorage,
+        UID.EnhancedCTImageStorage,
+        UID.NuclearMedicineImageStorage,
+        UID.UltrasoundMultiFrameImageStorageRetired,
+        UID.UltrasoundMultiFrameImageStorage,
+        UID.MRImageStorage,
+        UID.EnhancedMRImageStorage,
+        UID.MRSpectroscopyStorage,
+        UID.RTImageStorage,
+        UID.RTDoseStorage,
+        UID.RTStructureSetStorage,
+        UID.RTBeamsTreatmentRecordStorage,
+        UID.RTPlanStorage,
+        UID.RTBrachyTreatmentRecordStorage,
+        UID.RTTreatmentSummaryRecordStorage,
+        UID.NuclearMedicineImageStorageRetired,
+        UID.UltrasoundImageStorageRetired,
+        UID.UltrasoundImageStorage,
+        UID.RawDataStorage,
+        UID.SpatialRegistrationStorage,
+        UID.SpatialFiducialsStorage,
+        UID.RealWorldValueMappingStorage,
+        UID.SecondaryCaptureImageStorage,
+        UID.MultiFrameSingleBitSecondaryCaptureImageStorage,        
+        UID.MultiFrameGrayscaleByteSecondaryCaptureImageStorage,
+        UID.MultiFrameGrayscaleWordSecondaryCaptureImageStorage,
+        UID.MultiFrameTrueColorSecondaryCaptureImageStorage,
+        UID.VLImageStorageTrialRetired, /** updated */ 
+        UID.VLEndoscopicImageStorage,
+        UID.VideoEndoscopicImageStorage,
+        UID.VLMicroscopicImageStorage,
+        UID.VideoMicroscopicImageStorage,
+        UID.VLSlideCoordinatesMicroscopicImageStorage,
+        UID.VLPhotographicImageStorage,
+        UID.VideoPhotographicImageStorage,
+        UID.OphthalmicPhotography8BitImageStorage,
+        UID.OphthalmicPhotography16BitImageStorage,
+        UID.StereometricRelationshipStorage,
+        UID.VLMultiFrameImageStorageTrialRetired, /** updated */ 
+        UID.StandaloneOverlayStorageRetired,
+        UID.BasicTextSRStorage, /** updated  */ 
+        UID.EnhancedSRStorage, /** updated */ 
+        UID.ComprehensiveSRStorage, /** updated */ 
+        UID.ProcedureLogStorage,
+        UID.MammographyCADSRStorage, /** updated */
+        UID.KeyObjectSelectionDocumentStorage, /** updated */ 
+        UID.ChestCADSRStorage, /** updated */ 
+        UID.StandaloneCurveStorageRetired,
+        //UID._12leadECGWaveformStorage,
+        UID.GeneralECGWaveformStorage,
+        UID.AmbulatoryECGWaveformStorage,
+        UID.HemodynamicWaveformStorage,
+        UID.CardiacElectrophysiologyWaveformStorage,
+        UID.BasicVoiceAudioWaveformStorage,
+        UID.HangingProtocolStorage,
+        UID.SiemensCSANonImageStorage,
+        UID.VLWholeSlideMicroscopyImageStorage,
+        UID.BreastTomosynthesisImageStorage
+        };
+
+    public static synchronized SOPList getInstance()
+    {
+        if (instance == null) {
+            instance = new SOPList();
+        }
+        return instance;
+    }
+    
+    /**
+     * Creates a new list 
+     */
+    private SOPList() {
+        table = new Hashtable<String, TransfersStorage>();
+        
+        table.put(UID.CTImageStorage, new TransfersStorage());
+        table.put(UID.UltrasoundImageStorage, new TransfersStorage());
+        
+        for(int i=0; i<SOP.length; i++)
+        {
+            table.put(SOP[i], new TransfersStorage());
+        }        
+    }     
+    
+    /**
+     * If configuration file has no information, assume default settings
+     */
+    public synchronized void setDefaultSettings()
+    {
+        TransfersStorage TS;
+        for(int i=0; i<SOP.length; i++)
+        {
+            TS = table.get(SOP[i]);
+            TS.setDefaultSettings();
+        }
+    }
+    
+    /**
+     * Add a SOP Class to the list 
+     * @param UID SOP Class
+     * @return -1 if something went wrong, 1 otherwise
+     */
+    public synchronized int registerSOP(String UID) {
+                
+        if(table.containsKey(UID)) {
+            return -1;
+        }
+        
+        table.put(UID, new TransfersStorage());
+        
+        return 1;
+    }
+    
+    /**
+     * Given a SOP Class returns it's Tranfer Syntaxes
+     * @param UID SOP Class
+     * @return List of tranfer syntaxes for the given SOP Class
+     */
+    public synchronized  TransfersStorage getTS(String UID) {
+        TransfersStorage TS;
+        boolean [] p = null;
+        
+        TS = table.get(UID);
+        return TS;        
+    }    
+    
+    /**
+     * Updates a given SOP Class accepted Tranfer Syntaxes
+     * @param UID SOP Class
+     * @param p Transfer Syntaxes accepted on a boolean array
+     * @param a Globaly accept/reject this SOP Class
+     * @return -1 if something went wrong, 1 otherwise
+     */
+    public synchronized int updateTS(String UID, boolean [] p, boolean a) {
+        TransfersStorage TS;
+        TS = table.get(UID);
+        
+        if (TS != null) {
+            if(TS.setTS(p) != 0)
+            {
+                return -1;
+            }
+            TS.setAccepted(a);
+        }        
+        return 0;    
+    }   
+    /**
+     * Updates a given SOP Class accepted Tranfer Syntaxes
+     * @param UID SOP Class
+     * @param name
+     * @param vale
+     * @return -1 if something went wrong, 1 otherwise
+     */
+    public synchronized int updateTSField(String UID, String name, boolean value) {
+        logger.debug("UID: {}, name: {}, value: {}", UID, name, value);
+
+        TransfersStorage TS;
+        TS = table.get(UID);
+        
+        int index = -1;
+        for (int i = 0; i < TransfersStorage.globalTransferMap.size(); i++) {
+			if (TransfersStorage.globalTransferMap.get(i).equals(name)) {
+				index = i;
+				break;
+			}
+		}
+        if(TS !=null && index != -1)
+        {
+        	if(TS.setTS(value, index) != 0)
+        	{
+        		return -1;
+        	}
+        }
+        logger.debug("UID: {}, name: {}, value: {}", UID, name, value);
+      
+        return 0;    
+    }   
+    
+    /**
+     * Remove a SOP Class from List
+     * @param UID SOP Class
+     */
+     public synchronized void RemoveSOP(String UID) {
+         table.remove(UID);
+     }
+     
+     /**
+      * Removes selected services that do not have accepted transfers syntaxes 
+      */
+     public synchronized void CleanList()
+     {
+        List l = new ArrayList();
+        Enumeration e = table.keys();
+        TransfersStorage TS;        
+        boolean [] p;
+        boolean unused;
+        int i;
+        int j;
+        while(e.hasMoreElements())
+        {
+            l.add(e.nextElement().toString());
+        }        
+        for(i=0;i<l.size();i++)
+        {        
+            unused = true;
+            TS = table.get(l.get(i).toString());
+            if(TS.getAccepted())
+            {
+                p = TS.getTS();
+                for(j=0; j<p.length; j++)
+                {
+                    if(p[j])
+                    {
+                        unused = false;
+                        break;
+                    }
+                }
+                if(unused)
+                {
+                    TS.setAccepted(false);
+                }
+            }              
+            
+        }        
+     }
+     
+     /**
+      * Get the name of all the SOP Classes used in list
+      * @return List with all the identifiers of SOP Class currently in use
+      */ 
+     public synchronized List getKeys()
+     {
+        List l = new ArrayList();        
+        Enumeration e = table.keys();
+        
+        while(e.hasMoreElements())
+        {            
+            l.add(e.nextElement().toString());
+        }        
+        return l;
+     }
+     
+     /**
+      * Get the number of SOP Classes that are marked as accepted
+      * @return The number of SOP Classes that are actually marked as accepted
+      */
+     public synchronized int getAccepted()
+     {
+        List l = new ArrayList();    
+        TransfersStorage local;
+        Enumeration e = table.keys();
+        
+        while(e.hasMoreElements())
+        {            
+            l.add(e.nextElement().toString());
+        }
+        
+        int count = 0;
+        for(int i =0; i<l.size();i++)
+        {
+            local = table.get(l.get(i));
+            if (local != null)
+            {
+                if(local.getAccepted())
+                {
+                    count++;
+                }
+            }
+        }
+        return count;
+     }
+    
+     public String getSOPList(){
+    	 JSONArray sopList = new JSONArray();
+    	 for(String uid : SOP)
+    	 {	 JSONObject elem = new JSONObject();
+    	 	 elem.put("uid", uid);
+    	 	 elem.put("sop_name", SOPClassSettings.getInstance().getSOPClasses().get(uid));
+    		 JSONArray options = new JSONArray();
+    		 TransfersStorage ts = getTS(uid);
+    		 for(int i = 0; i< ts.getTS().length; i++)
+    		 {
+    			 JSONObject tsobj = new JSONObject();
+    			 String name = ts.globalTransferMap.get(i);
+    			 boolean value = ts.getTS()[i];
+    			 tsobj.put("name", name);
+    			 tsobj.put("value", value);
+    			 
+    			 options.add(tsobj);
+    		 }
+    		 elem.put("options", options);
+    		 sopList.add(elem);
+    		 
+    		 
+    	 }
+    	 return sopList.toString();
+    	 
+     }
+    
+            
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/SearchDicomResult.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/SearchDicomResult.java
new file mode 100755
index 0000000..e274cb0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/SearchDicomResult.java
@@ -0,0 +1,411 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** 
+ * Class SearchResult is responsible to get results from Lucene indexer
+ * But no text results are returned instead we use names of DICOM file and 
+ * instance a new DicomObject, so in theory this is an abstract to a list of 
+ * DicomObject, neither list of *names* of DICOM file.
+ */
+package pt.ua.dicoogle.server;
+
+import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.dcm4che2.data.*;
+import org.slf4j.Logger;
+import pt.ua.dicoogle.core.ServerSettings;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.LoggerFactory;
+
+import org.dcm4che2.io.DicomInputStream;
+
+
+import pt.ua.dicoogle.core.dim.*;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @since 17 Fev 2009
+ */
+public class SearchDicomResult implements Iterator<DicomObject>
+{
+
+    public enum QUERYLEVEL { PATIENT, STUDY, SERIE, IMAGE}
+
+    private final QUERYLEVEL queryLevel; 
+
+
+    /**
+    * Get IndexCore
+    */
+    
+    Collection<SearchResult> list = null ;
+    List<Patient> patientList = new ArrayList<>();
+    List<Study> studyList = new ArrayList<>();
+    List<Serie> seriesList = new ArrayList<>();
+    Iterator it = null ;
+    
+    String currentFile ;
+
+
+
+    private static ConcatTags concatTags = null;
+    private static  boolean concatTagsCheck = true;
+
+
+    private static final Logger logger = LoggerFactory.getLogger(SearchDicomResult.class);
+
+    public SearchDicomResult(String searchQuery, boolean isNetwork,
+			ArrayList<String> extrafields, QUERYLEVEL level) {
+
+		queryLevel = level;
+
+		/**
+		 * Get the array list of resulst match searchQuery
+		 */
+
+        logger.info("QUERY: " + searchQuery);
+        logger.info("QUERYLEVEL: " + queryLevel);
+
+        if (concatTags==null&& concatTagsCheck)
+        {
+            concatTags = new ConcatTags();
+            try {
+                concatTags.parseConfig(ConcatTags.FILENAME);
+            } catch (FileNotFoundException ex) {
+                logger.info("There is not file: " + ConcatTags.FILENAME);
+                concatTags = null;
+                concatTagsCheck = false;
+            }
+        }
+
+		HashMap<String, String> extraFields = new HashMap<String, String>();
+		for (String s : extrafields) {
+			extraFields.put(s, s);
+		}
+
+		JointQueryTask holder = new JointQueryTask() {
+
+			@Override
+			public void onReceive(Task<Iterable<SearchResult>> e) {
+				// TODO Auto-generated method stub
+
+			}
+
+			@Override
+			public void onCompletion() {
+				// TODO Auto-generated method stub
+
+			}
+		};
+		holder = PluginController.getInstance().queryAll(holder, searchQuery,
+				extraFields);
+
+		try {
+			it = holder.get().iterator();
+			
+			list = new ArrayList<SearchResult>();
+			while (it.hasNext()) {
+				list.add((SearchResult) it.next());
+			}
+		} catch (InterruptedException | ExecutionException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+
+		if(list != null)
+			it = list.iterator();
+		
+		if (level == QUERYLEVEL.PATIENT || level == QUERYLEVEL.STUDY) {
+			DIMGeneric dimModel = null;
+            try
+            {
+                if (concatTags==null)
+                    dimModel = new DIMGeneric(list);
+                else
+                    dimModel = new DIMGeneric(concatTags, list);
+
+            } catch (Exception ex)
+            {
+                ex.printStackTrace();
+            }
+
+			ArrayList<Patient> listPatients = dimModel.getPatients();
+
+			for (Patient p : listPatients) {
+				studyList.addAll(p.getStudies());
+			}
+
+			it = studyList.iterator();
+
+		} else if (level == QUERYLEVEL.SERIE) {
+
+            DIMGeneric dimModel = null;
+            try
+            {
+                if (concatTags==null)
+                    dimModel = new DIMGeneric(list);
+                else
+                    dimModel = new DIMGeneric(concatTags, list);
+            } catch (Exception ex)
+            {
+            }
+            
+
+			ArrayList<Patient> listPatients = dimModel.getPatients();
+			for (Patient p : listPatients) {
+				studyList.addAll(p.getStudies());
+				for (Study s : p.getStudies()) {
+					seriesList.addAll(s.getSeries());
+				}
+			}
+			it = seriesList.iterator();
+
+		}
+
+	}
+
+    @Override
+    public boolean hasNext()
+    {
+      if (it!=null)
+      {
+        return it.hasNext();
+      }
+      else
+      {
+        return false;
+      }
+    }
+
+    public String getCurrentFile()
+    {
+        return this.currentFile ; 
+    }
+
+    @Override
+    public DicomObject next()
+    {
+
+        // TODO: this code need to be refactored
+        // C-FIND RSP should be builded based on Search Result,
+        // instead opening the file to build DicomObject.
+
+        /** 
+         * Get the fullpath of images 
+         */
+        ServerSettings s = ServerSettings.getInstance();
+        String path = s.getPath(); 
+        
+        //DebugManager.getInstance().debug("Path of DICOM: "+path);
+
+
+        if (it != null &&  it.hasNext())
+        {
+            Object next = it.next();
+            if (queryLevel==QUERYLEVEL.IMAGE )
+            {
+
+                SearchResult sR = (SearchResult)next;
+                
+                path = sR.getURI().toString();
+                currentFile = path ;
+                //DebugManager.getInstance().debug("-> Next::: " + next.toString());
+                DicomInputStream din = null;
+                /*try
+                {
+                    if (path.endsWith(".gz"))
+                        din = new DicomInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(new File(path)), 256)));
+                    else
+                        din = new DicomInputStream(new File(path));
+                   
+                    
+                    URI uri = new URI(path);
+                    //System.out.println("Trying to find Plugin for: "+uri.toString());
+                    StorageInterface plug = PluginController.getInstance().getStorageForSchema(uri);
+                    
+                    if(plug != null){
+                        //System.out.println("Found Plugin For: "+uri.toString());
+                        
+                        Iterable<StorageInputStream> stream = plug.at(uri);
+                        for(StorageInputStream str : stream)
+                            
+                            try {
+                                din = new DicomInputStream(str.getInputStream());
+                            } catch (IOException ex) {
+                                LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
+                            }
+                    }
+                    
+                    //DebugManager.getInstance().debug("Imagem: "+path+"..."+next);
+                } catch (URISyntaxException ex) {
+                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
+                }
+                */
+                
+                /** This code is refactored in a experimental branch
+                 * Building a BasicDicomObject based on Indexing
+                 * It will increase the performace
+                 */
+                BasicDicomObject result = new BasicDicomObject();
+
+                // Fill fields of study now
+
+
+                //System.out.println("Serie : "+ serieTmp);
+                result.putString(Tag.InstitutionName, VR.CS,(String)sR.get("InstitutionName"));
+
+                result.putString(Tag.StudyInstanceUID, VR.UI, (String)sR.get("StudyInstanceUID"));
+                result.putString(Tag.SeriesInstanceUID, VR.UI, (String)sR.get("SeriesInstanceUID"));
+                result.putString(Tag.SOPInstanceUID, VR.UI, (String)sR.get("SOPInstanceUID"));
+                result.putString(Tag.SeriesDescription, VR.LO, (String)sR.get("SeriesDescription"));
+                result.putString(Tag.SeriesDate, VR.TM, (String)sR.get("SeriesDate"));
+                result.putString(Tag.SeriesTime, VR.TM, (String)sR.get("SeriesTime"));
+                result.putString(Tag.QueryRetrieveLevel, VR.LO, "IMAGE");
+
+                result.putString(Tag.Modality, VR.CS,(String)sR.get("Modality"));
+
+                result.putString(Tag.SeriesNumber, VR.IS, "" + (String)sR.get("SeriesNumber"));
+
+
+                return result;
+
+            }
+            else if (queryLevel == QUERYLEVEL.STUDY||queryLevel == QUERYLEVEL.PATIENT)
+            {
+
+                Study studyTmp = (Study)next;
+                BasicDicomObject result = new BasicDicomObject();
+                String patientName =studyTmp.getParent().getPatientName() ;
+                
+                try {
+                    patientName = new String(studyTmp.getParent().getPatientName().getBytes("ISO-8859-1"), "ISO-8859-1");
+                } catch (Exception ex) {
+                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
+                }
+                try {
+                    result.putBytes(Tag.PatientName, VR.PN, patientName.getBytes("ISO-8859-1"));
+                } catch (Exception ex) {
+                    LoggerFactory.getLogger(SearchDicomResult.class).error(ex.getMessage(), ex);
+                }
+                
+                //System.out.println("PatientName:"+patientName);
+                result.putString(Tag.SpecificCharacterSet, VR.CS, "ISO_IR 100");
+                result.putString(Tag.PatientSex, VR.LO, studyTmp.getParent().getPatientSex());
+                result.putString(Tag.PatientID, VR.LO, studyTmp.getParent().getPatientID());
+                result.putString(Tag.PatientBirthDate, VR.DA, studyTmp.getParent().getPatientBirthDate());
+                result.putString(Tag.StudyDate, VR.DA, studyTmp.getStudyData());
+                result.putString(Tag.StudyID, VR.SH, studyTmp.getStudyID());
+                result.putString(Tag.StudyTime, VR.TM, studyTmp.getStudyTime());
+                result.putString(Tag.AccessionNumber, VR.SH, studyTmp.getAccessionNumber());
+                result.putString(Tag.StudyInstanceUID, VR.UI, studyTmp.getStudyInstanceUID());
+                result.putString(Tag.StudyDescription, VR.LO, studyTmp.getStudyDescription());
+                String modality = studyTmp.getSeries().get(0).getModality(); // Point of Failure, fix me
+                result.putString(Tag.ModalitiesInStudy, VR.CS,modality);
+                result.putString(Tag.Modality, VR.CS,modality);
+                result.putString(Tag.InstitutionName, VR.CS, studyTmp.getInstitutuionName());
+
+                int instances = 0;
+                for (Serie serieTmp : studyTmp.getSeries())
+                {
+                    instances+=serieTmp.getImageList().size();
+                }
+
+                result.putString(Tag.NumberOfStudyRelatedInstances, VR.IS,""+instances);
+                result.putString(Tag.NumberOfSeriesRelatedInstances, VR.IS,""+studyTmp.getSeries().size());
+
+
+                return result;
+                
+            }
+            else if (queryLevel == QUERYLEVEL.SERIE)
+            {
+                // Serie
+
+                Serie serieTmp = (Serie)next;
+                BasicDicomObject result = new BasicDicomObject();
+                //System.out.println("Serie : "+ serieTmp);
+                result.putString(Tag.InstitutionName, VR.CS,serieTmp.getParent().getInstitutuionName());
+                
+                result.putString(Tag.StudyInstanceUID, VR.UI, serieTmp.getParent().getStudyInstanceUID());
+                result.putString(Tag.SeriesInstanceUID, VR.UI, serieTmp.getSerieInstanceUID());
+                result.putString(Tag.SeriesDescription, VR.LO, serieTmp.getSeriesDescription());
+                result.putString(Tag.SeriesDate, VR.TM, serieTmp.getSeriesDate());
+                result.putString(Tag.QueryRetrieveLevel, VR.LO, "SERIES");
+                String modality = serieTmp.getModality(); // Point of Failure, fix me
+                result.putString(Tag.Modality, VR.CS,modality);
+                
+                result.putString(Tag.SeriesNumber, VR.IS, "" + serieTmp.getSerieNumber());
+
+
+                result.putString(Tag.Modality, VR.CS,modality);
+                if (serieTmp.getModality().equals("MG")||serieTmp.getModality().equals("CR"))
+                {
+
+                    result.putString(Tag.ViewPosition, null, serieTmp.getViewPosition());
+                    result.putString(Tag.ImageLaterality, null, serieTmp.getImageLaterality());
+                    result.putString(Tag.AcquisitionDeviceProcessingDescription, VR.AE, serieTmp.getAcquisitionDeviceProcessingDescription());
+                    DicomElement viewCodeSequence = result.putSequence(Tag.ViewCodeSequence);
+                    DicomObject viewCodeSequenceObj = new BasicDicomObject();
+                    viewCodeSequenceObj.setParent(result);
+                    viewCodeSequenceObj.putString(Tag.CodeValue, null, serieTmp.getViewCodeSequence_CodeValue());
+                    viewCodeSequenceObj.putString(Tag.CodingSchemeDesignator, null, serieTmp.getViewCodeSequence_CodingSchemeDesignator());
+                    viewCodeSequenceObj.putString(Tag.CodingSchemeVersion, null, serieTmp.getViewCodeSequence_CodingSchemeVersion());
+                    viewCodeSequenceObj.putString(Tag.CodeMeaning, null, serieTmp.getViewCodeSequence_CodeMeaning());
+
+                    viewCodeSequence.addDicomObject(viewCodeSequenceObj);
+                    result.putNestedDicomObject(Tag.ViewCodeSequence, viewCodeSequenceObj);
+                }
+                result.putString(Tag.NumberOfSeriesRelatedInstances, VR.IS,""+serieTmp.getImageList().size());
+
+
+                result.putString(Tag.SeriesNumber, VR.IS, "" + serieTmp.getSerieNumber());
+                result.putString(Tag.ProtocolName, VR.LO, "" + serieTmp.getProtocolName());
+                result.putString(Tag.BodyPartThickness, VR.LO, "" + serieTmp.getBodyPartThickness());
+
+
+                return result;
+
+            }
+            else
+            {
+                System.err.println("ERROR: WRONG QUERY LEVEL!");
+            }
+            
+
+        }    
+        return null ; 
+    }
+
+    @Override
+    public void remove()
+    {
+        throw new UnsupportedOperationException("Not supported. Nobody use it.");
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/TransfersStorage.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/TransfersStorage.java
new file mode 100755
index 0000000..68a9d29
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/TransfersStorage.java
@@ -0,0 +1,225 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.dcm4che2.data.UID;
+
+/**
+ *
+ * @author Marco Pereira
+ * @author Frederico Silva
+ */
+public class TransfersStorage {
+    private boolean accepted;
+    private boolean [] TS;
+    
+    /*  [0] ImplicitVRLittleEndian
+     *  [1] ExplicitVRLittleEndian
+     *  [2] DeflatedExplicitVRLittleEndian
+     *  [3] ExplicitVRBigEndian
+     *  [4] JPEGLossless
+     *  [5] JPEGLSLossless
+     *  [6] JPEGLosslessNonHierarchical14
+     *  [7] JPEG2000LosslessOnly
+     *  [8] JPEGBaseline1
+     *  [9] JPEGExtended24
+     * [10] JPEGLSLossyNearLossless
+     * [11] JPEG2000
+     * [12] RLELossless
+     * [13] MPEG2
+     */
+    
+    public static final Map<Integer, String> globalTransferMap;
+    static {
+        Map<Integer, String> aMap = new HashMap<>();
+        aMap.put(0, "ImplicitVRLittleEndian");
+        aMap.put(1, "ExplicitVRLittleEndian");
+        aMap.put(2, "DeflatedExplicitVRLittleEndian");
+        aMap.put(3, "ExplicitVRBigEndian");
+        aMap.put(4, "JPEGLossless");
+        aMap.put(5, "JPEGLSLossless");
+        aMap.put(6, "JPEGLosslessNonHierarchical14");
+        aMap.put(7, "JPEG2000LosslessOnly");
+        aMap.put(8, "JPEGBaseline1");
+        aMap.put(9, "JPEGExtended24");
+        aMap.put(10, "JPEGLSLossyNearLossless");
+        aMap.put(11, "JPEG2000");
+        aMap.put(12, "RLELossless");
+        aMap.put(13, "MPEG2");
+        globalTransferMap = Collections.unmodifiableMap(aMap);
+    }
+    public TransfersStorage()
+    {
+        int i;
+        accepted = false;
+        TS = new boolean [14];
+        for(i = 0; i< TS.length; i++)
+        {
+            TS[i] = false;
+        }        
+    }
+
+    public void setAccepted(boolean status)
+    {
+        accepted = status;
+    }
+    
+    public boolean getAccepted()
+    {
+        return accepted;
+    }
+    
+    public int setTS(boolean [] status)
+    {
+        int i;
+       
+        if (status.length != 14)
+        {
+            return -1;
+        }
+        
+        for(i=0; i<status.length; i++)
+        {
+            TS[i] = status[i];
+        }
+        
+        return 0;
+    }
+    
+    public int setTS(boolean status, int index)
+    {
+        int i;
+       
+        if(index < 0 || index > 13)
+        {
+            return -1;
+        }     
+        TS[index] = status;
+        
+        return 0;
+    }
+            
+    public boolean[] getTS()
+    {
+        return TS;
+    }
+    
+    public void setDefaultSettings()
+    {
+        TS[0] = true;
+        TS[1] = true;
+        TS[4] = true;
+        TS[5] = true;
+        TS[8] = true;
+        accepted = true;
+        
+    }
+    
+    public String [] getVerboseTS()
+    {
+        int i, count =0;
+        String [] return_value = null;
+        for(i= 0; i<14; i++)
+        {
+            if(TS[i])
+            {
+                count++;
+            }
+        }
+        if(count > 0)
+        {
+            i = 0;
+            return_value = new String[count];
+            if (TS[0])
+            {
+                return_value[i] = UID.ImplicitVRLittleEndian;
+                i++;
+            }
+            if (TS[1])
+            {
+                return_value[i] = UID.ExplicitVRLittleEndian;
+                i++;
+            }
+            if (TS[2])
+            {
+                return_value[i] = UID.DeflatedExplicitVRLittleEndian;
+                i++;
+            }
+            if (TS[3])
+            {
+                return_value[i] = UID.ExplicitVRBigEndian;
+                i++;
+            }
+            if (TS[4])
+            {
+                return_value[i] = UID.JPEGLossless;
+                i++;
+            }
+            if (TS[5])
+            {
+                return_value[i] = UID.JPEGLSLossless;
+                i++;
+            }
+            if (TS[6])
+            {
+                return_value[i] = UID.JPEGLosslessNonHierarchical14;
+                i++;
+            }
+            if (TS[7])
+            {
+                return_value[i] = UID.JPEG2000LosslessOnly;
+                i++;
+            }
+            if (TS[8])
+            {
+                return_value[i] = UID.JPEGBaseline1;
+                i++;
+            }
+            if (TS[9])
+            {
+                return_value[i] = UID.JPEGExtended24;
+                i++;
+            }
+            if (TS[10])
+            {
+                return_value[i] = UID.JPEGLSLossyNearLossless;
+                i++;
+            }
+            if (TS[11])
+            {
+                return_value[i] = UID.JPEG2000;
+                i++;
+            }
+            if (TS[12])
+            {
+                return_value[i] = UID.RLELossless;
+                i++;
+            }
+            if (TS[13])
+            {
+                return_value[i] = UID.MPEG2;
+                i++;
+            }
+        }        
+        return return_value;        
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEvent.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEvent.java
new file mode 100755
index 0000000..bc94b3c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEvent.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.callbacks;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+
+
+public interface LogEvent
+{
+    public void startService(Object o);
+    public void stopService(Object o);
+
+}
+
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventAfter.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventAfter.java
new file mode 100755
index 0000000..5883ad3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventAfter.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.callbacks;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface LogEventAfter
+{
+    public void doAfter(Object o);
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventBefore.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventBefore.java
new file mode 100755
index 0000000..4a86b16
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/callbacks/LogEventBefore.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.callbacks;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface LogEventBefore extends LogEvent
+
+{
+    public void doBefore(Object o);
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindBuilder.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindBuilder.java
new file mode 100755
index 0000000..ddfaaf7
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindBuilder.java
@@ -0,0 +1,386 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+
+import pt.ua.dicoogle.core.exceptions.CFindNotSupportedException;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ *
+ *  [SOP Class name] -  [SOP Class UID]
+ *   Patient Root Q/R Find - 1.2.840.10008.5.1.4.1.2.1.1
+ *   Study Root Q/R Find - 1.2.840.10008.5.1.4.1.2.2.1
+ *   NOT SUPPORTED: @depracated
+ *   Patient-Study Root Q/R Find (Retired) - 1.2.840.10008.5.1.4.1.2.3.1
+ *
+ *
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CFindBuilder
+{
+
+    private boolean patientRoot = false ;
+    private boolean studyRoot = false ;
+
+    private String query = "";
+    
+
+    public CFindBuilder(DicomObject key, DicomObject rsp) throws CFindNotSupportedException
+    {
+
+        //if (!setRoot(rsp))
+        //    throw new CFindNotSupportedException() ;
+
+              
+        /**
+         * Sample output
+        (0008,0005) CS #10 [ISO_IR 100] Specific Character Set
+        (0008,0020) DA #18 [20090531-20090531] Study Date
+        (0008,0030) TM #22 [000000.000-120000.000] Study Time
+        (0008,0050) SH #0 [] Accession Number
+        (0008,0052) CS #6 [STUDY] Query/Retrieve Level
+        (0008,0061) CS #2 [XA] Modalities in Study
+        (0008,1030) LO #0 [] Study Description
+        (0010,0010) PN #0 [] Patient's Name
+        (0010,0020) LO #0 [] Patient ID
+        (0010,0030) DA #0 [] Patient's Birth Date
+        (0020,000D) UI #0 [] Study Instance UID
+        (0020,0010) SH #0 [] Study ID
+        (0020,1208) IS #0 [] Number of Study Related Instances
+         */
+
+        /** Search by required fields
+
+         *
+         *
+        */
+
+        // Get Affected SOP Classs UID
+        DicomElement elem = rsp.get(Integer.parseInt("00000002", 16));
+        String affectedSOP = new String(elem.getBytes());
+
+        TagsStruct tagstruct = TagsStruct.getInstance();
+        
+        //TagsStruct.getInstance().toStringNew();
+        boolean all=false ;
+        String append = "" ;
+        query="";
+        System.out.println(tagstruct.getDIMFields().size());
+        Iterator<TagValue> it = tagstruct.getDIMFields().iterator();
+        while(it.hasNext())
+        {
+            /** Verify if this tags exists
+            */
+        	TagValue tag = it.next();
+            int k = tag.getTagNumber() ;
+            DicomElement e = key.get(k);
+            //DebugManager.getInstance().debug("get key::"+ k );
+            if (e!=null)
+            {
+                String value = new String(e.getBytes());
+                //DebugManager.getInstance().debug("Value getted in CFIND RP:<"+t.get(k).getAlias() + "> "+ value  +".");
+                if (value.equals(""))
+                {
+                    continue ;
+
+                }
+                else
+                {
+                    value=value.trim();
+                    boolean modified = false ;
+                    // TODO :: Study Date need to be rewritted
+                    // and others weird tags like // should be mapped to lucene!
+                    if (k == Tag.ModalitiesInStudy)
+                    {
+                        String [] modality = value.split("\\\\");
+                        int i = 0 ;
+                        String modalityQuery = "";
+                        for (String mod : modality )
+                        {
+
+                            //DebugManager.getInstance().debug(mod);
+
+                            if (modified)
+                            {
+                                // There is already exist a modality
+                                modalityQuery += " OR ";
+                            }
+
+                            i++ ; 
+                            modified = true ;
+                            modalityQuery += "Modality" + ":" + mod;
+                        }
+                        if (!modalityQuery.equals(""))
+                        {
+                            System.err.println(modalityQuery);
+                            query = query + append +  " (" + modalityQuery + ")" ;
+                        }
+                        
+                    }
+
+                    else if(k == Tag.StudyDate)
+                    {
+                        System.out.println("Value :@" +value+".");
+                        
+                        String [] date = value.split("-");
+                        int i = 0 ;
+                        if (date.length==1)
+                        {
+                            
+                            if (!value.contains("-"))
+                            {
+                                query = query + append +tag.getAlias() + ":[" + date[0] + " TO " +
+                                date[0] + "]" ;
+                            }
+                            else
+                            {
+                                
+                                 String s;
+                                 Format formatter;
+                                 Date date2 = new Date();
+
+                                 // 01/09/02
+                                 formatter = new SimpleDateFormat("YYYYMMdd");
+                                 s = formatter.format(date2);
+
+                                 query = query + append +tag.getAlias() + ":[" + date[0] + " TO " +
+                                 s + "]" ;
+                            }
+                            
+                            
+                            //query = query +append + t.get(k).getAlias() + ":[" + date[0] + " TO " +
+                            //    date[0] + "]" ;
+                        }
+                        else if(date.length==2)
+                        {
+                            query = query + append + tag.getAlias() + ":[" + date[0] + " TO " +
+                                date[1] + "]" ;
+                        }
+                        modified = true ;
+                    }
+                    
+                    
+                    else if(k == Tag.StudyTime)
+                    {
+                        String [] date = value.split("-");
+                        int i = 0 ;
+                        if (date.length==1)
+                        {
+                            query = query + append +tag.getAlias() + ":[" + date[0] + " TO " +
+                                date[0] + "]" ;
+                            /*if (!value.contains("-"))
+                            {
+                                query = query + append +t.get(k).getAlias() + ":[" + date[0] + " TO " +
+                                date[0] + "]" ;
+                            }
+                            else
+                            {
+                                
+                                 String s;
+                                 Format formatter;
+                                 Date date2 = new Date();
+
+                                 // 01/09/02
+                                 formatter = new SimpleDateFormat("YYYYMMdd");
+                                 s = formatter.format(date2);
+
+                                 query = query + append +t.get(k).getAlias() + ":[" + date[0] + " TO " +
+                                 s + "]" ;
+                            }*/
+                        }
+                        else if(date.length==2)
+                        {
+                            query = query + append + tag.getAlias() + ":[" + date[0] + " TO " +
+                                date[1] + "]" ;
+                        }
+                        modified = true ;
+                    }
+                    
+                    
+
+                    else
+                    {
+                        modified = true ; 
+                        query += append + tag.getAlias() + ":" + value;
+                    }
+
+                    if (modified && it.hasNext())
+                    {
+                        append = " AND ";
+                    }
+
+                }
+
+            }
+        }
+        
+        if (query.equals(""))
+            query="*:*"; 
+        //DebugManager.getInstance().debug(">> Query String DICOM: "+ query);
+
+
+    }
+
+    public String getQueryString()
+            {
+        return this.query;
+    }
+
+    private synchronized  boolean setRoot(DicomObject rsp)
+    {
+        /**
+         * Verify if it is inside of:
+         * Affected SOP Class UID (0000,0002)
+         * Checked in C-FIND RQ in DICOM
+         * It is one of three ([P|S|PS] Root )
+         */
+
+        DicomElement elem = rsp.get(Integer.parseInt("00000002", 16));
+        String affectedSOP = new String(elem.getBytes());
+
+
+
+        //DebugManager.getInstance().debug(">" + affectedSOP);
+        //DebugManager.getInstance().debug(">> "+ServerSettings.getInstance().getSOPClass());
+        
+
+
+        boolean found = false;
+
+        for (String i : ServerSettings.getInstance().getSOPClass().split("\\|"))
+        {
+            //DebugManager.getInstance().debug("It have in settings:>: " + i);
+
+            if (affectedSOP.equals(i))
+            {
+                /**
+                1.2.840.10008.5.1.4.1.2.1.1 (Patient)
+                1.2.840.10008.5.1.4.1.2.2.1 (Study)
+                 */
+                //DebugManager.getInstance().debug(">>> Affected SOPs in ");
+                if (affectedSOP.equals("1.2.840.10008.5.1.4.1.2.1.1"))
+                {
+                    this.patientRoot = true ;
+                    found = true ;
+                }
+                else if (affectedSOP.equals("1.2.840.10008.5.1.4.1.2.2.1"))
+                {
+                    this.studyRoot = true ;
+                    found = true  ;
+                }
+                break ;
+            }
+        }
+
+        return found ;
+
+    }
+
+
+
+    /**
+     * @return the patientRoot
+     */
+    public boolean isPatientRoot()
+    {
+        return patientRoot;
+    }
+
+    /**
+     * @param patientRoot the patientRoot to set
+     */
+    public void setPatientRoot(boolean patientRoot)
+    {
+        this.patientRoot = patientRoot;
+    }
+
+    /**
+     * @return the studyRoot
+     */
+    public boolean isStudyRoot()
+    {
+        return studyRoot;
+    }
+
+    /**
+     * @param studyRoot the studyRoot to set
+     */
+    public void setStudyRoot(boolean studyRoot)
+    {
+        this.studyRoot = studyRoot;
+    }
+
+    /**
+     * @return the query
+     */
+    public String getQuery()
+    {
+        return query;
+    }
+
+    /**
+     * @param query the query to set
+     */
+    public void setQuery(String query)
+    {
+        this.query = query;
+    }
+
+
+    public static boolean isPatientRoot(DicomObject rsp)
+    {
+        DicomElement elem = rsp.get(Integer.parseInt("00000002", 16));
+        String affectedSOP = new String(elem.getBytes());
+
+        if (affectedSOP.equals("1.2.840.10008.5.1.4.1.2.2.1"))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean isStudyRoot(DicomObject rsp)
+    {
+        DicomElement elem = rsp.get(Integer.parseInt("00000002", 16));
+        String affectedSOP = new String(elem.getBytes());
+        if (affectedSOP.equals("1.2.840.10008.5.1.4.1.2.1.1"))
+        {
+            return true;
+        }
+        return false;
+    }
+    
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindServiceSCP.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindServiceSCP.java
new file mode 100755
index 0000000..a5be6e1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CFindServiceSCP.java
@@ -0,0 +1,199 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import aclmanager.core.LuceneQueryACLManager;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.concurrent.Executor;
+
+import org.dcm4che2.data.*;
+
+
+import javax.xml.transform.TransformerConfigurationException;
+
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.DicomServiceException;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.service.CFindService;
+
+
+import pt.ua.dicoogle.DicomLog.LogDICOM;
+import pt.ua.dicoogle.DicomLog.LogLine;
+
+
+import pt.ua.dicoogle.DicomLog.LogXML;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.server.controllers.Logs;
+
+
+
+import pt.ua.dicoogle.server.DicomNetwork;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CFindServiceSCP extends CFindService {
+
+    private ServerSettings s = ServerSettings.getInstance();
+    private int rspdelay = ServerSettings.getInstance().getRspDelay();
+    
+    private DicomNetwork service = null;
+    private LuceneQueryACLManager luke = null;
+
+    private boolean superSpeed = false;
+    
+
+    public CFindServiceSCP(String[] multiSop, Executor e) {
+        super(multiSop, e);
+        this.luke = null;        
+    }
+
+    public CFindServiceSCP(String[] multiSop, Executor e, LuceneQueryACLManager luke) {
+        super(multiSop, e);
+        this.luke = luke;        
+    }
+    
+    /*** CFIND */
+    @Override
+    protected synchronized DimseRSP doCFind(Association as, int pcid,
+            DicomObject cmd, DicomObject keys, DicomObject rsp)
+            throws DicomServiceException {
+
+        //DebugManager.getInstance().debug("doCFind? -- > working on it");
+
+
+        DimseRSP replay = null;
+
+        /**
+         * ///  How create a new Connection? Detect new connections..
+        if (MainWindow.getMw() != null) {
+        MainWindow.getMw().newClientConnection(as);
+        }
+         */
+        /**
+         * Verify Permited AETs
+         */
+        //DebugManager.getInstance().debug(":: Verify Permited AETs @??C-FIND Action ");
+        boolean permited = false;
+
+        if (s.getPermitAllAETitles()) {
+            permited = true;
+        } else {
+            String permitedAETs[] = s.getCAET();
+
+            for (int i = 0; i < permitedAETs.length; i++) {
+                if (permitedAETs[i].equals(as.getCallingAET())) {
+                    permited = true;
+                    break;
+                }
+            }
+        }
+
+
+        if (!permited) {
+            //DebugManager.getInstance().debug("Client association NOT permited: " + as.getCallingAET() + "!");
+            //as.abort();
+
+            //return new FindRSP(keys, rsp, null);
+        } else {
+            //DebugManager.getInstance().debug("Client association permited: " + as.getCallingAET() + "!");
+        }
+
+
+        if (this.rspdelay > 0) {
+            try {
+                this.wait(this.rspdelay);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+
+        /**
+         * Search information at Lucene Indexer
+         * So the FindRSP will fill the DimRSP
+         */
+        replay = new FindRSP(keys, rsp,  as.getCallingAET(), luke);
+
+
+        DicomElement e = keys.get(Tag.PatientName);
+        String add = "";
+        if (e != null) {
+            add = new String(e.getBytes());
+        }
+
+        String queryParams = "";
+
+        for (Iterator<DicomElement> iterator = keys.iterator(); iterator.hasNext();)
+        {
+            DicomElement element = iterator.next();
+
+            if (!element.isEmpty())
+            {
+                if (!ElementDictionary.getDictionary().nameOf(element.tag()).contains("Sequence"))
+                    queryParams += ElementDictionary.getDictionary().nameOf(element.tag()) + " - " + element.getValueAsString(new SpecificCharacterSet("UTF-8"), 0) + " ";
+            }
+        }
+        if (!superSpeed)
+        {
+            LogLine ll = new LogLine("cfind", getDateTime(), as.getCallingAET(),
+                    as.toString() + " -- " + add, queryParams);
+            LogDICOM.getInstance().addLine(ll);
+
+            synchronized (LogDICOM.getInstance()) {
+                LogXML l = new LogXML();
+                try {
+                    l.printXML();
+                } catch (TransformerConfigurationException ex) {
+                    ex.printStackTrace();
+                }
+            }
+
+        }
+        //Logs.getInstance().addLog(ll);
+
+
+        return replay;
+    }
+
+    private String getDateTime() {
+        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        Date date = new Date();
+        return dateFormat.format(date);
+    }
+
+    /**
+     * @return the service
+     */
+    public DicomNetwork getService() {
+        return service;
+    }
+
+    /**<
+     * @param service the service to set
+     */
+    public void setService(DicomNetwork service) {
+        this.service = service;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveService.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveService.java
new file mode 100755
index 0000000..ca06308
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveService.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.io.IOException;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.DicomServiceException;
+import org.dcm4che2.net.service.CMoveSCP;
+import org.dcm4che2.net.service.DicomService;
+import java.util.concurrent.Executor;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.SingleDimseRSP;
+import org.dcm4che2.net.Status;
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CMoveService extends DicomService implements CMoveSCP
+{
+
+
+    private final Executor executor;
+
+    public CMoveService(String[] sopClasses, Executor executor)
+    {
+        super(sopClasses);
+        this.executor = executor;
+    }
+
+    public CMoveService(String sopClass, Executor executor)
+    {
+        super(sopClass);
+        this.executor = executor;
+    }
+
+ at Override
+    public void cmove(Association as, int pcid, DicomObject rq,
+            DicomObject data) throws DicomServiceException, IOException
+    {
+                //DebugManager.getInstance().debug("just cmove");
+
+        //DebugManager.getInstance().debug(CommandUtils.toString(rq, pcid, "1.2.2.2.2.2.2.0"));
+        DicomObject cmdrsp = CommandUtils.mkRSP(rq, CommandUtils.SUCCESS);
+        DimseRSP rsp = doCMove(as, pcid, rq, data, cmdrsp);
+        try {
+            rsp.next();
+        } catch (InterruptedException e) {
+            throw new DicomServiceException(rq, Status.ProcessingFailure);
+        }
+        cmdrsp = rsp.getCommand();
+        if (CommandUtils.isPending(cmdrsp))
+        {
+            as.registerCancelRQHandler(rq, rsp);
+            //executor.execute(new WriteMultiDimseRsp(as, pcid, rsp));
+        }
+        else
+        {
+            as.writeDimseRSP(pcid, cmdrsp, rsp.getDataset());
+        }
+    }
+    protected DimseRSP doCMove(Association as, int pcid, DicomObject cmd,
+            DicomObject data, DicomObject rsp) throws DicomServiceException
+    {
+        return new SingleDimseRSP(rsp);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveServiceSCP.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveServiceSCP.java
new file mode 100755
index 0000000..1a008ce
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CMoveServiceSCP.java
@@ -0,0 +1,323 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import aclmanager.core.LuceneQueryACLManager;
+import aclmanager.models.Principal;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+
+import org.dcm4che2.data.Tag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.xml.transform.TransformerConfigurationException;
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.DicomServiceException;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.Status;
+import pt.ua.dicoogle.core.exceptions.CFindNotSupportedException;
+
+import pt.ua.dicoogle.DicomLog.LogDICOM;
+import pt.ua.dicoogle.DicomLog.LogLine;
+import pt.ua.dicoogle.DicomLog.LogXML;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.server.DicomNetwork;
+import pt.ua.dicoogle.server.SearchDicomResult;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.rGUI.server.controllers.Logs;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CMoveServiceSCP extends CMoveService {
+
+    private DicomNetwork service = null;
+    private LuceneQueryACLManager luke;
+
+    public CMoveServiceSCP(String[] sopClasses, Executor executor, LuceneQueryACLManager luke) {
+        super(sopClasses, executor);
+         this.luke = luke;
+    }
+
+    public CMoveServiceSCP(String sopClass, Executor executor) {
+        super(sopClass, executor);
+        this.luke = null;
+    }
+    
+    
+    @Override
+    protected DimseRSP doCMove(Association as, int pcid, DicomObject cmd,
+            DicomObject data, DicomObject rsp) throws DicomServiceException {
+        //DebugManager.getInstance().debug("doCMove");
+        //DebugManager.getInstance().debug("DoCmove");
+
+        DimseRSP replay = null;
+
+        /**
+         * Verify Permited AETs
+         */
+        //DebugManager.getInstance().debug(":: Verify Permited AETs @??C-MOVE Action ");
+
+        boolean permited = false;
+
+        if (ServerSettings.getInstance().getPermitAllAETitles()) {
+            permited = true;
+        } else 
+        {
+            String permitedAETs[] = ServerSettings.getInstance().getCAET();
+
+            for (int i = 0; i < permitedAETs.length; i++) {
+                if (permitedAETs[i].equals(as.getCallingAET())) {
+                    permited = true;
+                    break;
+                }
+            }
+        }
+
+        if (!permited) {
+            //DebugManager.getInstance().debug("Client association NOT permited: " + as.getCallingAET() + "!");
+            as.abort();
+
+            return new MoveRSP(data, rsp);
+        } else {
+            //DebugManager.getInstance().debug("Client association permited: " + as.getCallingAET() + "!");
+        }
+
+        /** FIXME: Write wait by rspreplay */
+        try {
+            Thread.sleep(ServerSettings.getInstance().getRspDelay());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+
+
+        /**
+         *
+         * Now it is the code to move
+         * In this sense it have a fork, besides we can open the store request
+         * in the source direction, or it can make a store to a third party
+         *
+         */
+        /** Get the real IP to move */
+        InetAddress ip = as.getSocket().getInetAddress();
+        /** Get the port to move */
+        int portAddr = as.getSocket().getPort();
+
+        String destination = cmd.getString(org.dcm4che2.data.Tag.MoveDestination);
+        //DebugManager.getInstance().debug("A Move was required to <ip:port> : <"
+        //        + ip.getHostAddress() + ":" + portAddr + ">" + " to --> " + destination);
+
+
+
+        /** Verify if it have the field destination */
+        if (destination == null) {
+            throw new DicomServiceException(cmd, Status.UnrecognizedOperation,
+                    "Missing Move Destination");
+        }
+
+        /*DebugManager.getInstance().debug("-- Objects containing the data requested by C-MOVE");
+        DebugManager.getInstance().debug(data.toString());
+        DebugManager.getInstance().debug(cmd.toString());
+        DebugManager.getInstance().debug(rsp.toString());*/
+        String SOPUID = new String(data.get(Integer.parseInt("0020000D", 16)).getBytes());
+        String CMoveID = cmd.getString(org.dcm4che2.data.Tag.MessageID);
+        System.out.println("C-MOVE ID REQUEST: " + CMoveID);
+        
+        /**
+         * Get object to search
+         */
+        ArrayList<String> extrafields = null;
+        extrafields = new ArrayList<String>();
+
+        extrafields.add("PatientName");
+        extrafields.add("PatientID");
+        extrafields.add("Modality");
+        extrafields.add("StudyDate");
+        extrafields.add("Thumbnail");
+        extrafields.add("StudyInstanceUID");
+        
+        SearchDicomResult.QUERYLEVEL level = null;
+        if (CFindBuilder.isPatientRoot(rsp)) {
+            level = SearchDicomResult.QUERYLEVEL.PATIENT;
+        } else if (CFindBuilder.isStudyRoot(rsp)) {
+            level = SearchDicomResult.QUERYLEVEL.STUDY;
+        }
+
+        CFindBuilder cfind = null;
+        try {
+            cfind = new CFindBuilder(data, rsp);
+        } catch (CFindNotSupportedException ex) {
+            ex.printStackTrace();
+        }
+        String query = cfind.getQueryString();
+               
+        if(luke != null){
+            String filterQuery = luke.produceQueryFilter(new Principal("AETitle", as.getCallingAET()));
+            if(query.length() > 0 )
+                 query += filterQuery;
+        }
+        //TODO: FIlter Query;
+        SearchDicomResult search = new SearchDicomResult(query,
+                true, extrafields, SearchDicomResult.QUERYLEVEL.IMAGE);
+        ArrayList<URI> files = new ArrayList<URI>();
+
+
+
+
+        if (search == null) {
+            //DebugManager.getInstance().debug(">> Search is null, so"
+            //        + " somethig is wrong ");
+        } else {
+
+            while (search.hasNext()) {
+                DicomObject obj = search.next();
+                DicomElement e = obj.get(Integer.parseInt("0020000D", 16));
+                String tmp = null;
+                if (e != null) {
+                    tmp = new String(e.getBytes());
+                }
+                if (SOPUID != null && tmp != null) {
+                    //files.add(new File(search.getCurrentFile()));
+                    String uriString = search.getCurrentFile();
+                     
+                    try {
+                        URI nURI = new URI(uriString);
+                        
+                           files.add(nURI);
+                    } catch (URISyntaxException ex) {
+                        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
+                    }
+                }
+
+            }
+        }
+
+
+
+
+
+        if (files.size() != 0) {
+
+            /**
+             * What is the destination?
+             *
+             */
+            String hostDest = ip.getHostAddress();
+            ServerSettings ob = ServerSettings.getInstance();
+            for (MoveDestination m : ob.getMoves()) {
+                if (m.getAETitle().equals(destination)) {
+                    hostDest = m.getIpAddrs();
+                    portAddr = m.getPort();
+                }
+            }
+
+
+
+            LogLine ll = new LogLine("cmove", LogLine.getDateTime(), destination,
+                    "Files: " + files.size() + " -- (" + hostDest + ":" + portAddr + ")","studyUID="+data.getString(Tag.StudyInstanceUID));
+            LogDICOM.getInstance().addLine(ll);
+
+            synchronized (LogDICOM.getInstance()) {
+                try {
+                    LogXML l = new LogXML();
+                    l.printXML();
+                } catch (TransformerConfigurationException ex) {
+                    LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
+                }
+            }
+
+            //Logs.getInstance().addLog(ll);
+            if (CMoveID==null||CMoveID.equals(""))
+            {
+                //DebugManager.getInstance().debug("No originator message ID");
+                return null;
+            }
+            try
+            {
+                System.out.println("Destination: " + destination);
+                new CallDCMSend(files, portAddr, hostDest, destination, CMoveID);
+            } catch (Exception ex)
+            {
+                ex.printStackTrace();
+                //DebugManager.getInstance().debug("Error Sending files to Storage Server!");
+            }
+        }
+
+        /** UnNecessary now 
+
+        // put a BufferedReader on the ls output
+
+        InputStream inputstream =
+        proc.getInputStream();
+        InputStreamReader inputstreamreader =
+        new InputStreamReader(inputstream);
+        BufferedReader bufferedreader =
+        new BufferedReader(inputstreamreader);
+
+        // read the ls output
+
+        String line;
+        try
+        {
+        while ((line = bufferedreader.readLine()) != null)
+        {
+        System.out.println(">>>"+line);
+        }
+        //replay = new MoveRSP(keys, rsp, this.core); // Third Party Move
+        } catch (IOException ex)
+        {
+        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
+        }
+        try
+        {
+        Thread.sleep(100);
+        //replay = new MoveRSP(keys, rsp, this.core); // Third Party Move
+        } catch (InterruptedException ex)
+        {
+        LoggerFactory.getLogger(CMoveServiceSCP.class).error(ex.getMessage(), ex);
+        }
+         */
+        replay = new MoveRSP(data, rsp); // Third Party Move
+        return replay;
+
+    }
+
+    /**
+     * @return the service
+     */
+    public DicomNetwork getService() {
+        return service;
+    }
+
+    /**
+     * @param service the service to set
+     */
+    public void setService(DicomNetwork service) {
+        this.service = service;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CallDCMSend.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CallDCMSend.java
new file mode 100755
index 0000000..60eee40
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/CallDCMSend.java
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import com.google.common.io.ByteStreams;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import org.dcm4che2.io.DicomInputStream;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CallDCMSend
+{
+
+    public CallDCMSend(ArrayList<File> files, int port, String hostname, String AETitle, String cmoveID) throws Exception
+    {
+
+             DcmSnd dcmsnd = new DcmSnd();
+             
+
+            dcmsnd.setRemoteHost(hostname);
+            dcmsnd.setRemotePort(port);
+            
+            for (File fx : files)
+            {
+                File f = fx;
+                dcmsnd.addFile(f);
+            }
+            dcmsnd.setCalledAET(AETitle);
+     
+        dcmsnd.configureTransferCapability();
+//            try {
+//                dcmsnd.initTLS();
+//            } catch (Exception e) {
+//                System.err.println("ERROR: Failed to initialize TLS context:"
+//                        + e.getMessage());
+//                System.exit(2);
+//            }
+        
+         dcmsnd.setMoveOriginatorMessageID(cmoveID);
+         dcmsnd.start();
+         dcmsnd.open();
+         dcmsnd.send();
+         dcmsnd.close();
+         
+      
+        }
+
+     public CallDCMSend(List<URI> files, int port, String hostname, String AETitle, String cmoveID) throws Exception
+    {
+
+             DcmSndV2 dcmsnd = new DcmSndV2();
+             
+
+            dcmsnd.setRemoteHost(hostname);
+            dcmsnd.setRemotePort(port);
+            
+            for (URI rui : files)
+            {                
+                System.out.println("Entered Retrieving: "+rui.toString());
+                StorageInterface plugin = PluginController.getInstance().getStorageForSchema(rui);
+                System.out.println("Plkugin: " +  plugin);
+                System.out.println("rui.toString: " +  plugin);
+                
+                
+                if(plugin != null)
+                {
+                    System.out.println("Retrieving: "+rui.toString());
+                    try{
+                    System.out.println("Retrieving: "+rui.toString());
+                    Iterable<StorageInputStream> it = plugin.at(rui);
+                    
+                    for( StorageInputStream iStream : it)
+                    {
+                        byte[] byteArr = ByteStreams.toByteArray(new DicomInputStream(iStream.getInputStream()));
+                        dcmsnd.addFile(ByteBuffer.wrap(byteArr));
+                        System.out.println("Added NewFile: "+rui.toString());
+                    }
+                    
+                    /*InputStream retrievedFile = plugin.retrieve(rui); 
+                    byte[] byteArr = ByteStreams.toByteArray(retrievedFile);
+                    dcmsnd.addFile(ByteBuffer.wrap(byteArr));
+                    System.out.println("Added NewFile: "+rui.toString());*/
+                    }catch(IOException ex){
+                        ex.printStackTrace();
+                    }
+                }           
+            }
+            dcmsnd.setCalledAET(AETitle);
+     
+        dcmsnd.configureTransferCapability();
+//            try {
+//                dcmsnd.initTLS();
+//            } catch (Exception e) {
+//                System.err.println("ERROR: Failed to initialize TLS context:"
+//                        + e.getMessage());
+//                System.exit(2);
+//            }
+        
+         dcmsnd.setMoveOriginatorMessageID(cmoveID);
+         dcmsnd.start();
+         dcmsnd.open();
+         dcmsnd.send();
+         dcmsnd.close();
+         
+      
+        }
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSnd.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSnd.java
new file mode 100755
index 0000000..b14e2fe
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSnd.java
@@ -0,0 +1,931 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.zip.GZIPInputStream;
+
+
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.UID;
+import org.dcm4che2.data.UIDDictionary;
+import org.dcm4che2.data.VR;
+import org.dcm4che2.io.DicomInputStream;
+import org.dcm4che2.io.DicomOutputStream;
+import org.dcm4che2.io.StopTagInputHandler;
+import org.dcm4che2.io.TranscoderInputHandler;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.ConfigurationException;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.DimseRSPHandler;
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+import org.dcm4che2.net.NewThreadExecutor;
+import org.dcm4che2.net.NoPresentationContextException;
+import org.dcm4che2.net.PDVOutputStream;
+import org.dcm4che2.net.TransferCapability;
+import org.dcm4che2.net.UserIdentity;
+import org.dcm4che2.net.service.StorageCommitmentService;
+import org.dcm4che2.util.CloseUtils;
+import org.dcm4che2.util.StringUtils;
+import org.dcm4che2.util.UIDUtils;
+import pt.ua.dicoogle.core.ServerSettings;
+
+/**
+ * @author gunter zeilinger(gunterze at gmail.com)
+ * @version $Revision: 10933 $ $Date: 2009-04-21 01:48:38 +0100 (Ter, 21 Abr 2009) $
+ * @since Oct 13, 2005
+ */
+public class DcmSnd extends StorageCommitmentService {
+
+    private static final int KB = 1024;
+
+    private static final int MB = KB * KB;
+
+    private static final int PEEK_LEN = 1024;
+
+    private static final String USAGE =
+        "dcmsnd [Options] <aet>[@<host>[:<port>]] <file>|<directory>...";
+
+    private static final String DESCRIPTION =
+        "\nLoad composite DICOM Object(s) from specified DICOM file(s) and send it "
+      + "to the specified remote Application Entity. If a directory is specified,"
+      + "DICOM Object in files under that directory and further sub-directories "
+      + "are sent. If <port> is not specified, DICOM default port 104 is assumed. "
+      + "If also no <host> is specified, localhost is assumed. Optionally, a "
+      + "Storage Commitment Request for successfully tranferred objects is sent "
+      + "to the remote Application Entity after the storage. The Storage Commitment "
+      + "result is accepted on the same association or - if a local port is "
+      + "specified by option -L - in a separate association initiated by the "
+      + "remote Application Entity\n"
+      + "OPTIONS:";
+
+    private static final String EXAMPLE =
+        "\nExample: dcmsnd -stgcmt -L DCMSND:11113 STORESCP at localhost:11112 image.dcm \n"
+      + "=> Start listening on local port 11113 for receiving Storage Commitment "
+      + "results, send DICOM object image.dcm to Application Entity STORESCP, "
+      + "listening on local port 11112, and request Storage Commitment in same association.";
+
+    private static String[] TLS1 = { "TLSv1" };
+
+    private static String[] SSL3 = { "SSLv3" };
+
+    private static String[] NO_TLS1 = { "SSLv3", "SSLv2Hello" };
+
+    private static String[] NO_SSL2 = { "TLSv1", "SSLv3" };
+
+    private static String[] NO_SSL3 = { "TLSv1", "SSLv2Hello" };
+
+    private static char[] SECRET = { 's', 'e', 'c', 'r', 'e', 't' };
+
+    private static final String[] ONLY_IVLE_TS = {
+        UID.ImplicitVRLittleEndian
+    };
+
+    private static final String[] IVLE_TS = {
+        UID.ImplicitVRLittleEndian,
+        UID.ExplicitVRLittleEndian,
+        UID.ExplicitVRBigEndian,
+    };
+
+    private static final String[] EVLE_TS = {
+        UID.ExplicitVRLittleEndian,
+        UID.ImplicitVRLittleEndian,
+        UID.ExplicitVRBigEndian,
+    };
+
+    private static final String[] EVBE_TS = {
+        UID.ExplicitVRBigEndian,
+        UID.ExplicitVRLittleEndian,
+        UID.ImplicitVRLittleEndian,
+    };
+
+    private static final int STG_CMT_ACTION_TYPE = 1;
+
+    /** TransferSyntax: DCM4CHE URI Referenced */
+    private static final String DCM4CHEE_URI_REFERENCED_TS_UID =
+            "1.2.40.0.13.1.1.2.4.94";
+
+    private Executor executor = new NewThreadExecutor("DCMSND");
+
+    private NetworkApplicationEntity remoteAE = new NetworkApplicationEntity();
+
+    private NetworkApplicationEntity remoteStgcmtAE;
+
+    private NetworkConnection remoteConn = new NetworkConnection();
+
+    private NetworkConnection remoteStgcmtConn = new NetworkConnection();
+
+    private Device device = new Device("DCMSND");
+
+    private NetworkApplicationEntity ae = new NetworkApplicationEntity();
+
+    private NetworkConnection conn = new NetworkConnection();
+
+    private Map<String, Set<String>> as2ts = new HashMap<String, Set<String>>();
+
+    private ArrayList<FileInfo> files = new ArrayList<FileInfo>();
+
+    private Association assoc;
+
+    private int priority = 0;
+
+    private int transcoderBufferSize = 1024;
+
+    private int filesSent = 0;
+
+    private long totalSize = 0L;
+
+    private boolean fileref = false;
+
+    private boolean stgcmt = false;
+
+    private long shutdownDelay = 1000L;
+
+    private DicomObject stgCmtResult;
+
+    private String keyStoreURL = "resource:tls/test_sys_1.p12";
+
+    private char[] keyStorePassword = SECRET;
+
+    private char[] keyPassword;
+
+    private String trustStoreURL = "resource:tls/mesa_certs.jks";
+
+    private char[] trustStorePassword = SECRET;
+    
+    private String MoveOriginatorMessageID = null;
+
+    private boolean gzip = ServerSettings.getInstance().isGzipStorage();
+    
+    public DcmSnd() {
+        remoteAE.setInstalled(true);
+        remoteAE.setAssociationAcceptor(true);
+        remoteAE.setNetworkConnection(new NetworkConnection[] { remoteConn });
+
+        device.setNetworkApplicationEntity(ae);
+        device.setNetworkConnection(conn);
+        ae.setNetworkConnection(conn);
+        ae.setAssociationInitiator(true);
+        ae.setAssociationAcceptor(true);
+        ae.register(this);
+        ae.setAETitle(ServerSettings.getInstance().getAE());
+    }
+
+    public final void setLocalHost(String hostname) {
+        conn.setHostname(hostname);
+    }
+
+    public final void setLocalPort(int port) {
+        conn.setPort(port);
+    }
+
+    public final void setRemoteHost(String hostname) {
+        remoteConn.setHostname(hostname);
+    }
+
+    public final void setRemotePort(int port) {
+        remoteConn.setPort(port);
+    }
+
+    public final void setRemoteStgcmtHost(String hostname) {
+        remoteStgcmtConn.setHostname(hostname);
+    }
+
+    public final void setRemoteStgcmtPort(int port) {
+        remoteStgcmtConn.setPort(port);
+    }
+
+    public final void setTlsProtocol(String[] tlsProtocol) {
+        conn.setTlsProtocol(tlsProtocol);
+    }
+
+    public final void setTlsWithoutEncyrption() {
+        conn.setTlsWithoutEncyrption();
+        remoteConn.setTlsWithoutEncyrption();
+        remoteStgcmtConn.setTlsWithoutEncyrption();
+    }
+
+    public final void setTls3DES_EDE_CBC() {
+        conn.setTls3DES_EDE_CBC();
+        remoteConn.setTls3DES_EDE_CBC();
+        remoteStgcmtConn.setTls3DES_EDE_CBC();
+    }
+
+    public final void setTlsAES_128_CBC() {
+        conn.setTlsAES_128_CBC();
+        remoteConn.setTlsAES_128_CBC();
+        remoteStgcmtConn.setTlsAES_128_CBC();
+    }
+
+    public final void setTlsNeedClientAuth(boolean needClientAuth) {
+        conn.setTlsNeedClientAuth(needClientAuth);
+    }
+
+    public final void setKeyStoreURL(String url) {
+        keyStoreURL = url;
+    }
+
+    public final void setKeyStorePassword(String pw) {
+        keyStorePassword = pw.toCharArray();
+    }
+
+    public final void setKeyPassword(String pw) {
+        keyPassword = pw.toCharArray();
+    }
+
+    public final void setTrustStorePassword(String pw) {
+        trustStorePassword = pw.toCharArray();
+    }
+
+    public final void setTrustStoreURL(String url) {
+        trustStoreURL = url;
+    }
+
+    public final void setCalledAET(String called) {
+        remoteAE.setAETitle(called);
+    }
+
+    public final void setCalling(String calling) {
+        ae.setAETitle(calling);
+    }
+
+    public final void setUserIdentity(UserIdentity userIdentity) {
+        ae.setUserIdentity(userIdentity);
+    }
+
+    public final void setOfferDefaultTransferSyntaxInSeparatePresentationContext(
+            boolean enable) {
+        ae.setOfferDefaultTransferSyntaxInSeparatePresentationContext(enable);
+    }
+
+    public final void setSendFileRef(boolean fileref) {
+        this.fileref = fileref;
+    }
+
+    public final void setStorageCommitment(boolean stgcmt) {
+        this.stgcmt = stgcmt;
+    }
+
+    public final boolean isStorageCommitment() {
+        return stgcmt;
+    }
+
+    public final void setStgcmtCalledAET(String called) {
+        remoteStgcmtAE = new NetworkApplicationEntity();
+        remoteStgcmtAE.setInstalled(true);
+        remoteStgcmtAE.setAssociationAcceptor(true);
+        remoteStgcmtAE.setNetworkConnection(
+                new NetworkConnection[] { remoteStgcmtConn });
+        remoteStgcmtAE.setAETitle(called);
+    }
+
+    public final void setShutdownDelay(int shutdownDelay) {
+        this.shutdownDelay = shutdownDelay;
+    }
+
+
+    public final void setConnectTimeout(int connectTimeout) {
+        conn.setConnectTimeout(connectTimeout);
+    }
+
+    public final void setMaxPDULengthReceive(int maxPDULength) {
+        ae.setMaxPDULengthReceive(maxPDULength);
+    }
+
+    public final void setMaxOpsInvoked(int maxOpsInvoked) {
+        ae.setMaxOpsInvoked(maxOpsInvoked);
+    }
+
+    public final void setPackPDV(boolean packPDV) {
+        ae.setPackPDV(packPDV);
+    }
+
+    public final void setAssociationReaperPeriod(int period) {
+        device.setAssociationReaperPeriod(period);
+    }
+
+    public final void setDimseRspTimeout(int timeout) {
+        ae.setDimseRspTimeout(timeout);
+    }
+
+    public final void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public final void setTcpNoDelay(boolean tcpNoDelay) {
+        conn.setTcpNoDelay(tcpNoDelay);
+    }
+
+    public final void setAcceptTimeout(int timeout) {
+        conn.setAcceptTimeout(timeout);
+    }
+
+    public final void setReleaseTimeout(int timeout) {
+        conn.setReleaseTimeout(timeout);
+    }
+
+    public final void setSocketCloseDelay(int timeout) {
+        conn.setSocketCloseDelay(timeout);
+    }
+
+    public final void setMaxPDULengthSend(int maxPDULength) {
+        ae.setMaxPDULengthSend(maxPDULength);
+    }
+
+    public final void setReceiveBufferSize(int bufferSize) {
+        conn.setReceiveBufferSize(bufferSize);
+    }
+
+    public final void setSendBufferSize(int bufferSize) {
+        conn.setSendBufferSize(bufferSize);
+    }
+
+    public final void setTranscoderBufferSize(int transcoderBufferSize) {
+        this.transcoderBufferSize = transcoderBufferSize;
+    }
+
+    public final int getNumberOfFilesToSend() {
+        return files.size();
+    }
+
+    public final int getNumberOfFilesSent() {
+        return filesSent;
+    }
+
+    public final long getTotalSizeSent() {
+        return totalSize;
+    }
+
+    public List<FileInfo> getFileInfos() {
+        return files;
+    }
+
+
+    private static void promptStgCmt(DicomObject cmtrslt, float seconds) {
+        
+        DicomElement refSOPSq = cmtrslt.get(Tag.ReferencedSOPSequence);
+        System.out.print(refSOPSq.countItems());
+        System.out.println(" successful");
+        DicomElement failedSOPSq = cmtrslt.get(Tag.FailedSOPSequence);
+        if (failedSOPSq != null) {
+            System.out.print(failedSOPSq.countItems());
+            System.out.println(" FAILED!");
+        }
+    }
+
+    private synchronized DicomObject waitForStgCmtResult() throws InterruptedException {
+        while (stgCmtResult == null) wait();
+        return stgCmtResult;
+    }
+
+    private static void prompt(DcmSnd dcmsnd, float seconds) {
+        System.out.print("\nSent ");
+        System.out.print(dcmsnd.getNumberOfFilesSent());
+        System.out.print(" objects (=");
+        promptBytes(dcmsnd.getTotalSizeSent());
+        System.out.print(") in ");
+        System.out.print(seconds);
+        System.out.print("s (=");
+        promptBytes(dcmsnd.getTotalSizeSent() / seconds);
+        System.out.println("/s)");
+    }
+
+    private static void promptBytes(float totalSizeSent) {
+        if (totalSizeSent > MB) {
+            System.out.print(totalSizeSent / MB);
+            System.out.print("MB");
+        } else {
+            System.out.print(totalSizeSent / KB);
+            System.out.print("KB");
+        }
+    }
+
+    private static int toPort(String port) {
+        return port != null ? parseInt(port, "illegal port number", 1, 0xffff)
+                : 104;
+    }
+
+    private static String[] split(String s, char delim) {
+        String[] s2 = { s, null };
+        int pos = s.indexOf(delim);
+        if (pos != -1) {
+            s2[0] = s.substring(0, pos);
+            s2[1] = s.substring(pos + 1);
+        }
+        return s2;
+    }
+
+    private static void exit(String msg) {
+        System.err.println(msg);
+        System.err.println("Try 'dcmsnd -h' for more information.");
+        System.exit(1);
+    }
+
+    private static int parseInt(String s, String errPrompt, int min, int max) {
+        try {
+            int i = Integer.parseInt(s);
+            if (i >= min && i <= max)
+                return i;
+        } catch (NumberFormatException e) {
+            // parameter is not a valid integer; fall through to exit
+        }
+        exit(errPrompt);
+        throw new RuntimeException();
+    }
+
+    public void addFile(File f) {
+        if (f.isDirectory()) {
+            File[] fs = f.listFiles();
+            for (int i = 0; i < fs.length; i++)
+                addFile(fs[i]);
+            return;
+        }
+        FileInfo info = new FileInfo(f);
+        DicomObject dcmObj = new BasicDicomObject();
+        DicomInputStream in = null;
+        try {
+            if (f.getAbsolutePath().endsWith(".gz"))
+            {
+                in = new DicomInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(f), 256)));
+            }
+            else
+            {
+                in = new DicomInputStream(f);
+            }
+            in.setHandler(new StopTagInputHandler(Tag.StudyDate));
+            in.readDicomObject(dcmObj, PEEK_LEN);
+            info.tsuid = in.getTransferSyntax().uid();
+            info.fmiEndPos = in.getEndOfFileMetaInfoPosition();
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.err.println("WARNING: Failed to parse " + f + " - skipped.");
+            System.out.print('F');
+            return;
+        } finally {
+            CloseUtils.safeClose(in);
+        }
+        info.cuid = dcmObj.getString(Tag.SOPClassUID);
+        if (info.cuid == null) {
+            System.err.println("WARNING: Missing SOP Class UID in " + f
+                    + " - skipped.");
+            System.out.print('F');
+            return;
+        }
+        info.iuid = dcmObj.getString(Tag.SOPInstanceUID);
+        if (info.iuid == null) {
+            System.err.println("WARNING: Missing SOP Instance UID in " + f
+                    + " - skipped.");
+            System.out.print('F');
+            return;
+        }
+        addTransferCapability(info.cuid, info.tsuid);
+        files.add(info);
+        System.out.print('.');
+    }
+
+    public void addTransferCapability(String cuid, String tsuid) {
+        Set<String> ts = as2ts.get(cuid);
+        if (fileref) {
+            if (ts == null) {
+                as2ts.put(cuid,
+                        Collections.singleton(DCM4CHEE_URI_REFERENCED_TS_UID));
+            }
+        } else {
+            if (ts == null) {
+                ts = new HashSet<String>();
+                ts.add(UID.ImplicitVRLittleEndian);
+                as2ts.put(cuid, ts);
+            }
+            ts.add(tsuid);
+        }
+    }
+    
+
+
+    public void configureTransferCapability() {
+        int off = stgcmt || remoteStgcmtAE != null ? 1 : 0;
+        TransferCapability[] tc = new TransferCapability[off + as2ts.size()];
+        if (off > 0) {
+            tc[0] = new TransferCapability(
+                    UID.StorageCommitmentPushModelSOPClass,
+                    ONLY_IVLE_TS,
+                    TransferCapability.SCU);
+        }
+        Iterator<Map.Entry<String, Set<String>>> iter = as2ts.entrySet().iterator();
+        for (int i = off; i < tc.length; i++) {
+            Map.Entry<String, Set<String>> e = iter.next();
+            String cuid = e.getKey();
+            Set<String> ts = e.getValue();
+            tc[i] = new TransferCapability(cuid,
+                    ts.toArray(new String[ts.size()]),
+                    TransferCapability.SCU);
+        }
+        ae.setTransferCapability(tc);
+    }
+
+    public void start() throws IOException {
+        if (conn.isListening()) {
+            conn.bind(executor );
+            System.out.println("Start Server listening on port " + conn.getPort());
+        }
+    }
+
+    public void stop() {
+        if (conn.isListening()) {
+            try {
+                Thread.sleep(shutdownDelay);
+            } catch (InterruptedException e) {
+                // Should not happen
+                e.printStackTrace();
+            }
+            conn.unbind();
+        }
+    }
+
+    public void open() throws IOException, ConfigurationException,
+            InterruptedException {
+        assoc = ae.connect(remoteAE, executor);
+    }
+
+    public void openToStgcmtAE() throws IOException, ConfigurationException,
+            InterruptedException {
+        assoc = ae.connect(remoteStgcmtAE, executor);
+    }
+
+    public void send() {
+        for (int i = 0, n = files.size(); i < n; ++i) {
+            FileInfo info = files.get(i);
+            TransferCapability tc = assoc.getTransferCapabilityAsSCU(info.cuid);
+            if (tc == null) {
+                System.out.println();
+                System.out.println(UIDDictionary.getDictionary().prompt(
+                        info.cuid)
+                        + " not supported by " + remoteAE.getAETitle());
+                System.out.println("skip file " + info.f);
+                continue;
+            }
+            
+            
+            String tsuid = selectTransferSyntax(tc.getTransferSyntax(),
+                    fileref ? DCM4CHEE_URI_REFERENCED_TS_UID : info.tsuid);
+            if (tsuid == null) {
+                System.out.println();
+                System.out.println(UIDDictionary.getDictionary().prompt(
+                        info.cuid)
+                        + " with "
+                        + UIDDictionary.getDictionary().prompt(
+                                fileref ? DCM4CHEE_URI_REFERENCED_TS_UID
+                                        : info.tsuid)
+                        + " not supported by " + remoteAE.getAETitle());
+                System.out.println("skip file " + info.f);
+                continue;
+            }
+
+            try {
+                DimseRSPHandler rspHandler = new DimseRSPHandler() {
+                    @Override
+                    public void onDimseRSP(Association as, DicomObject cmd,
+                            DicomObject data) {
+                        DcmSnd.this.onDimseRSP(cmd);
+                    }
+                };
+                
+                if(MoveOriginatorMessageID!=null)
+                {
+                    int messageID = Integer.parseInt(MoveOriginatorMessageID);
+                    assoc.cstore(info.cuid, info.iuid, priority, assoc.getCallingAET(), messageID,
+                        new DataWriter(info), tsuid, rspHandler);
+                }
+                else
+                {
+                    assoc.cstore(info.cuid, info.iuid, priority, 
+                        new DataWriter(info), tsuid, rspHandler);
+                }
+                
+                
+                
+                //assoc.cstore(info.cuid, info.iuid, priority, assoc.getCallingAET(), priority, new DataWriter(info), tsuid, rspHandler);
+                
+            } catch (NoPresentationContextException e) {
+                System.err.println("WARNING: " + e.getMessage()
+                        + " - cannot send " + info.f);
+                System.out.print('F');
+            } catch (IOException e) {
+                e.printStackTrace();
+                System.err.println("ERROR: Failed to send - " + info.f + ": "
+                        + e.getMessage());
+                System.out.print('F');
+            } catch (InterruptedException e) {
+                // should not happen
+                e.printStackTrace();
+            }
+        }
+        try {
+            assoc.waitForDimseRSP();
+        } catch (InterruptedException e) {
+            // should not happen
+            e.printStackTrace();
+        }
+    }
+
+    public boolean commit() {
+        DicomObject actionInfo = new BasicDicomObject();
+        actionInfo.putString(Tag.TransactionUID, VR.UI, UIDUtils.createUID());
+        
+        DicomElement refSOPSq = actionInfo.putSequence(Tag.ReferencedSOPSequence);
+        for (int i = 0, n = files.size(); i < n; ++i) {
+            FileInfo info = files.get(i);
+            if (info.transferred) {
+                BasicDicomObject refSOP = new BasicDicomObject();
+                
+                refSOP.putString(Tag.ReferencedSOPClassUID, VR.UI, info.cuid);
+                refSOP.putString(Tag.ReferencedSOPInstanceUID, VR.UI, info.iuid);
+
+                refSOPSq.addDicomObject(refSOP);
+            }
+        }
+        try {
+            stgCmtResult = null;
+            DimseRSP rsp = assoc.naction(UID.StorageCommitmentPushModelSOPClass,
+                UID.StorageCommitmentPushModelSOPInstance, STG_CMT_ACTION_TYPE,
+                actionInfo, UID.ImplicitVRLittleEndian);
+            rsp.next();
+            DicomObject cmd = rsp.getCommand();
+            int status = cmd.getInt(Tag.Status);
+            if (status == 0) {
+                return true;
+            }
+            System.err.println(
+                    "WARNING: Storage Commitment request failed with status: "
+                    + StringUtils.shortToHex(status) + "H");
+            System.err.println(cmd.toString());
+        } catch (NoPresentationContextException e) {
+            System.err.println("WARNING: " + e.getMessage()
+                    + " - cannot request Storage Commitment");
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.err.println(
+                    "ERROR: Failed to send Storage Commitment request: "
+                    + e.getMessage());
+        } catch (InterruptedException e) {
+            // should not happen
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    private String selectTransferSyntax(String[] available, String tsuid) {
+        if (tsuid.equals(UID.ImplicitVRLittleEndian))
+            return selectTransferSyntax(available, IVLE_TS);
+        if (tsuid.equals(UID.ExplicitVRLittleEndian))
+            return selectTransferSyntax(available, EVLE_TS);
+        if (tsuid.equals(UID.ExplicitVRBigEndian))
+            return selectTransferSyntax(available, EVBE_TS);
+        for (int j = 0; j < available.length; j++)
+            if (available[j].equals(tsuid))
+                return tsuid;
+        return null;
+    }
+
+    private String selectTransferSyntax(String[] available, String[] tsuids) {
+        for (int i = 0; i < tsuids.length; i++)
+            for (int j = 0; j < available.length; j++)
+                if (available[j].equals(tsuids[i]))
+                    return available[j];
+        return null;
+    }
+
+    public void close() {
+        try {
+            assoc.release(false);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @return the MoveOriginatorMessageID
+     */
+    public String getMoveOriginatorMessageID() {
+        return MoveOriginatorMessageID;
+    }
+
+    /**
+     * @param MoveOriginatorMessageID the MoveOriginatorMessageID to set
+     */
+    public void setMoveOriginatorMessageID(String MoveOriginatorMessageID) {
+        this.MoveOriginatorMessageID = MoveOriginatorMessageID;
+    }
+
+    public static final class FileInfo {
+        File f;
+
+        String cuid;
+
+        String iuid;
+
+        String tsuid;
+
+        long fmiEndPos;
+
+        long length;
+
+        boolean transferred;
+
+        int status;
+
+        public FileInfo(File f) {
+            this.f = f;
+            this.length = f.length();
+        }
+
+    }
+
+    
+    
+    private class DataWriter implements org.dcm4che2.net.DataWriter {
+
+        private FileInfo info;
+
+        public DataWriter(FileInfo info) {
+            this.info = info;
+        }
+
+        public void writeTo(PDVOutputStream out, String tsuid)
+                throws IOException {
+            if (tsuid.equals(info.tsuid)) {
+                InputStream fis = null;
+                if (info.f.getAbsolutePath().endsWith(".gz"))
+                    fis = new GZIPInputStream(new BufferedInputStream(new FileInputStream(info.f), 256));
+                else
+                    fis = new FileInputStream(info.f);
+                
+                try {
+                    long skip = info.fmiEndPos;
+                    while (skip > 0)
+                        skip -= fis.skip(skip);
+                    out.copyFrom(fis);
+                } finally {
+                    fis.close();
+                }
+            } else if (tsuid.equals(DCM4CHEE_URI_REFERENCED_TS_UID)) {
+                DicomObject attrs;
+                DicomInputStream dis = null;
+                if (info.f.getAbsolutePath().endsWith(".gz"))
+                {
+                    dis = new DicomInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(info.f), 256)));
+                }
+                else
+                {
+                    dis= new DicomInputStream(info.f);
+                }
+                
+                try {
+                    dis.setHandler(new StopTagInputHandler(Tag.PixelData));
+                    attrs = dis.readDicomObject();
+                } finally {
+                    dis.close();
+                }
+                DicomOutputStream dos = new DicomOutputStream(out);
+                attrs.putString(Tag.RetrieveURI, VR.UT, info.f.toURI().toString());
+                
+                dos.writeDataset(attrs, tsuid);
+             } else {
+                DicomInputStream dis = null;
+                if (info.f.getAbsolutePath().endsWith(".gz"))
+                {
+                     dis = new DicomInputStream(new GZIPInputStream(new BufferedInputStream(new FileInputStream(info.f), 256)));
+                }
+                else
+                {
+                    dis = new DicomInputStream(info.f);
+                }
+                try {
+                    DicomOutputStream dos = new DicomOutputStream(out);
+                    dos.setTransferSyntax(tsuid);
+                    TranscoderInputHandler h = new TranscoderInputHandler(dos,
+                            transcoderBufferSize);
+                    dis.setHandler(h);
+                    dis.readDicomObject();
+                } finally {
+                    dis.close();
+                }
+            }
+        }
+
+    }
+
+    private void promptErrRSP(String prefix, int status, FileInfo info,
+            DicomObject cmd) {
+        System.err.println(prefix + StringUtils.shortToHex(status) + "H for "
+                + info.f + ", cuid=" + info.cuid + ", tsuid=" + info.tsuid);
+        System.err.println(cmd.toString());
+    }
+
+    private void onDimseRSP(DicomObject cmd) {
+        int status = cmd.getInt(Tag.Status);
+        int msgId = cmd.getInt(Tag.MessageIDBeingRespondedTo);
+        FileInfo info = files.get(msgId - 1);
+        info.status = status;
+        switch (status) {
+        case 0:
+            info.transferred = true;
+            totalSize += info.length;
+            ++filesSent;
+            System.out.print('.');
+            break;
+        case 0xB000:
+        case 0xB006:
+        case 0xB007:
+            info.transferred = true;
+            totalSize += info.length;
+            ++filesSent;
+            promptErrRSP("WARNING: Received RSP with Status ", status, info,
+                    cmd);
+            System.out.print('W');
+            break;
+        default:
+            promptErrRSP("ERROR: Received RSP with Status ", status, info, cmd);
+            System.out.print('F');
+        }
+    }
+
+    @Override
+    protected synchronized void onNEventReportRSP(Association as, int pcid,
+            DicomObject rq, DicomObject info, DicomObject rsp) {
+        stgCmtResult = info;
+        notifyAll();
+    }
+
+    public void initTLS() throws GeneralSecurityException, IOException {
+        KeyStore keyStore = loadKeyStore(keyStoreURL, keyStorePassword);
+        KeyStore trustStore = loadKeyStore(trustStoreURL, trustStorePassword);
+        device.initTLS(keyStore,
+                keyPassword != null ? keyPassword : keyStorePassword,
+                trustStore);
+    }
+
+    private static KeyStore loadKeyStore(String url, char[] password)
+            throws GeneralSecurityException, IOException {
+        KeyStore key = KeyStore.getInstance(toKeyStoreType(url));
+        InputStream in = openFileOrURL(url);
+        try {
+            key.load(in, password);
+        } finally {
+            in.close();
+        }
+        return key;
+    }
+
+    private static InputStream openFileOrURL(String url) throws IOException {
+        if (url.startsWith("resource:")) {
+            return DcmSnd.class.getClassLoader().getResourceAsStream(
+                    url.substring(9));
+        }
+        try {
+            return new URL(url).openStream();
+        } catch (MalformedURLException e) {
+            return new FileInputStream(url);
+        }
+    }
+
+    private static String toKeyStoreType(String fname) {
+        return fname.endsWith(".p12") || fname.endsWith(".P12")
+                 ? "PKCS12" : "JKS";
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSndV2.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSndV2.java
new file mode 100755
index 0000000..56a5cf0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DcmSndV2.java
@@ -0,0 +1,908 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.io.*;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.zip.GZIPInputStream;
+
+
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.UID;
+import org.dcm4che2.data.UIDDictionary;
+import org.dcm4che2.data.VR;
+import org.dcm4che2.io.DicomInputStream;
+import org.dcm4che2.io.DicomOutputStream;
+import org.dcm4che2.io.StopTagInputHandler;
+import org.dcm4che2.io.TranscoderInputHandler;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.ConfigurationException;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.DimseRSPHandler;
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+import org.dcm4che2.net.NewThreadExecutor;
+import org.dcm4che2.net.NoPresentationContextException;
+import org.dcm4che2.net.PDVOutputStream;
+import org.dcm4che2.net.TransferCapability;
+import org.dcm4che2.net.UserIdentity;
+import org.dcm4che2.net.service.StorageCommitmentService;
+import org.dcm4che2.util.CloseUtils;
+import org.dcm4che2.util.StringUtils;
+import org.dcm4che2.util.UIDUtils;
+import pt.ua.dicoogle.core.ServerSettings;
+
+/**
+ * @author gunter zeilinger(gunterze at gmail.com)
+ * @version $Revision: 10933 $ $Date: 2009-04-21 01:48:38 +0100 (Ter, 21 Abr 2009) $
+ * @since Oct 13, 2005
+ */
+public class DcmSndV2 extends StorageCommitmentService {
+
+    private static final int KB = 1024;
+
+    private static final int MB = KB * KB;
+
+    private static final int PEEK_LEN = 1024;
+
+    private static final String USAGE =
+        "dcmsnd [Options] <aet>[@<host>[:<port>]] <file>|<directory>...";
+
+    private static final String DESCRIPTION =
+        "\nLoad composite DICOM Object(s) from specified DICOM file(s) and send it "
+      + "to the specified remote Application Entity. If a directory is specified,"
+      + "DICOM Object in files under that directory and further sub-directories "
+      + "are sent. If <port> is not specified, DICOM default port 104 is assumed. "
+      + "If also no <host> is specified, localhost is assumed. Optionally, a "
+      + "Storage Commitment Request for successfully tranferred objects is sent "
+      + "to the remote Application Entity after the storage. The Storage Commitment "
+      + "result is accepted on the same association or - if a local port is "
+      + "specified by option -L - in a separate association initiated by the "
+      + "remote Application Entity\n"
+      + "OPTIONS:";
+
+    private static final String EXAMPLE =
+        "\nExample: dcmsnd -stgcmt -L DCMSND:11113 STORESCP at localhost:11112 image.dcm \n"
+      + "=> Start listening on local port 11113 for receiving Storage Commitment "
+      + "results, send DICOM object image.dcm to Application Entity STORESCP, "
+      + "listening on local port 11112, and request Storage Commitment in same association.";
+
+    private static String[] TLS1 = { "TLSv1" };
+
+    private static String[] SSL3 = { "SSLv3" };
+
+    private static String[] NO_TLS1 = { "SSLv3", "SSLv2Hello" };
+
+    private static String[] NO_SSL2 = { "TLSv1", "SSLv3" };
+
+    private static String[] NO_SSL3 = { "TLSv1", "SSLv2Hello" };
+
+    private static char[] SECRET = { 's', 'e', 'c', 'r', 'e', 't' };
+
+    private static final String[] ONLY_IVLE_TS = {
+        UID.ImplicitVRLittleEndian
+    };
+
+    private static final String[] IVLE_TS = {
+        UID.ImplicitVRLittleEndian,
+        UID.ExplicitVRLittleEndian,
+        UID.ExplicitVRBigEndian,
+    };
+
+    private static final String[] EVLE_TS = {
+        UID.ExplicitVRLittleEndian,
+        UID.ImplicitVRLittleEndian,
+        UID.ExplicitVRBigEndian,
+    };
+
+    private static final String[] EVBE_TS = {
+        UID.ExplicitVRBigEndian,
+        UID.ExplicitVRLittleEndian,
+        UID.ImplicitVRLittleEndian,
+    };
+
+    private static final int STG_CMT_ACTION_TYPE = 1;
+
+    /** TransferSyntax: DCM4CHE URI Referenced */
+    private static final String DCM4CHEE_URI_REFERENCED_TS_UID =
+            "1.2.40.0.13.1.1.2.4.94";
+
+    private Executor executor = new NewThreadExecutor("DCMSND");
+
+    private NetworkApplicationEntity remoteAE = new NetworkApplicationEntity();
+
+    private NetworkApplicationEntity remoteStgcmtAE;
+
+    private NetworkConnection remoteConn = new NetworkConnection();
+
+    private NetworkConnection remoteStgcmtConn = new NetworkConnection();
+
+    private Device device = new Device("DCMSND");
+
+    private NetworkApplicationEntity ae = new NetworkApplicationEntity();
+
+    private NetworkConnection conn = new NetworkConnection();
+
+    private Map<String, Set<String>> as2ts = new HashMap<String, Set<String>>();
+
+    private ArrayList<FileInfo> files = new ArrayList<FileInfo>();
+
+    private Association assoc;
+
+    private int priority = 0;
+
+    private int transcoderBufferSize = 1024;
+
+    private int filesSent = 0;
+
+    private long totalSize = 0L;
+
+    private boolean fileref = false;
+
+    private boolean stgcmt = false;
+
+    private long shutdownDelay = 1000L;
+
+    private DicomObject stgCmtResult;
+
+    private String keyStoreURL = "resource:tls/test_sys_1.p12";
+
+    private char[] keyStorePassword = SECRET;
+
+    private char[] keyPassword;
+
+    private String trustStoreURL = "resource:tls/mesa_certs.jks";
+
+    private char[] trustStorePassword = SECRET;
+    
+    private String MoveOriginatorMessageID = null;
+
+    private boolean gzip = ServerSettings.getInstance().isGzipStorage();
+    
+    public DcmSndV2() {
+        remoteAE.setInstalled(true);
+        remoteAE.setAssociationAcceptor(true);
+        remoteAE.setNetworkConnection(new NetworkConnection[] { remoteConn });
+
+        device.setNetworkApplicationEntity(ae);
+        device.setNetworkConnection(conn);
+        ae.setNetworkConnection(conn);
+        ae.setAssociationInitiator(true);
+        ae.setAssociationAcceptor(true);
+        ae.register(this);
+        ae.setAETitle(ServerSettings.getInstance().getAE());
+    }
+
+    public final void setLocalHost(String hostname) {
+        conn.setHostname(hostname);
+    }
+
+    public final void setLocalPort(int port) {
+        conn.setPort(port);
+    }
+
+    public final void setRemoteHost(String hostname) {
+        remoteConn.setHostname(hostname);
+    }
+
+    public final void setRemotePort(int port) {
+        remoteConn.setPort(port);
+    }
+
+    public final void setRemoteStgcmtHost(String hostname) {
+        remoteStgcmtConn.setHostname(hostname);
+    }
+
+    public final void setRemoteStgcmtPort(int port) {
+        remoteStgcmtConn.setPort(port);
+    }
+
+    public final void setTlsProtocol(String[] tlsProtocol) {
+        conn.setTlsProtocol(tlsProtocol);
+    }
+
+    public final void setTlsWithoutEncyrption() {
+        conn.setTlsWithoutEncyrption();
+        remoteConn.setTlsWithoutEncyrption();
+        remoteStgcmtConn.setTlsWithoutEncyrption();
+    }
+
+    public final void setTls3DES_EDE_CBC() {
+        conn.setTls3DES_EDE_CBC();
+        remoteConn.setTls3DES_EDE_CBC();
+        remoteStgcmtConn.setTls3DES_EDE_CBC();
+    }
+
+    public final void setTlsAES_128_CBC() {
+        conn.setTlsAES_128_CBC();
+        remoteConn.setTlsAES_128_CBC();
+        remoteStgcmtConn.setTlsAES_128_CBC();
+    }
+
+    public final void setTlsNeedClientAuth(boolean needClientAuth) {
+        conn.setTlsNeedClientAuth(needClientAuth);
+    }
+
+    public final void setKeyStoreURL(String url) {
+        keyStoreURL = url;
+    }
+
+    public final void setKeyStorePassword(String pw) {
+        keyStorePassword = pw.toCharArray();
+    }
+
+    public final void setKeyPassword(String pw) {
+        keyPassword = pw.toCharArray();
+    }
+
+    public final void setTrustStorePassword(String pw) {
+        trustStorePassword = pw.toCharArray();
+    }
+
+    public final void setTrustStoreURL(String url) {
+        trustStoreURL = url;
+    }
+
+    public final void setCalledAET(String called) {
+        remoteAE.setAETitle(called);
+    }
+
+    public final void setCalling(String calling) {
+        ae.setAETitle(calling);
+    }
+
+    public final void setUserIdentity(UserIdentity userIdentity) {
+        ae.setUserIdentity(userIdentity);
+    }
+
+    public final void setOfferDefaultTransferSyntaxInSeparatePresentationContext(
+            boolean enable) {
+        ae.setOfferDefaultTransferSyntaxInSeparatePresentationContext(enable);
+    }
+
+    public final void setSendFileRef(boolean fileref) {
+        this.fileref = fileref;
+    }
+
+    public final void setStorageCommitment(boolean stgcmt) {
+        this.stgcmt = stgcmt;
+    }
+
+    public final boolean isStorageCommitment() {
+        return stgcmt;
+    }
+
+    public final void setStgcmtCalledAET(String called) {
+        remoteStgcmtAE = new NetworkApplicationEntity();
+        remoteStgcmtAE.setInstalled(true);
+        remoteStgcmtAE.setAssociationAcceptor(true);
+        remoteStgcmtAE.setNetworkConnection(
+                new NetworkConnection[] { remoteStgcmtConn });
+        remoteStgcmtAE.setAETitle(called);
+    }
+
+    public final void setShutdownDelay(int shutdownDelay) {
+        this.shutdownDelay = shutdownDelay;
+    }
+
+
+    public final void setConnectTimeout(int connectTimeout) {
+        conn.setConnectTimeout(connectTimeout);
+    }
+
+    public final void setMaxPDULengthReceive(int maxPDULength) {
+        ae.setMaxPDULengthReceive(maxPDULength);
+    }
+
+    public final void setMaxOpsInvoked(int maxOpsInvoked) {
+        ae.setMaxOpsInvoked(maxOpsInvoked);
+    }
+
+    public final void setPackPDV(boolean packPDV) {
+        ae.setPackPDV(packPDV);
+    }
+
+    public final void setAssociationReaperPeriod(int period) {
+        device.setAssociationReaperPeriod(period);
+    }
+
+    public final void setDimseRspTimeout(int timeout) {
+        ae.setDimseRspTimeout(timeout);
+    }
+
+    public final void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public final void setTcpNoDelay(boolean tcpNoDelay) {
+        conn.setTcpNoDelay(tcpNoDelay);
+    }
+
+    public final void setAcceptTimeout(int timeout) {
+        conn.setAcceptTimeout(timeout);
+    }
+
+    public final void setReleaseTimeout(int timeout) {
+        conn.setReleaseTimeout(timeout);
+    }
+
+    public final void setSocketCloseDelay(int timeout) {
+        conn.setSocketCloseDelay(timeout);
+    }
+
+    public final void setMaxPDULengthSend(int maxPDULength) {
+        ae.setMaxPDULengthSend(maxPDULength);
+    }
+
+    public final void setReceiveBufferSize(int bufferSize) {
+        conn.setReceiveBufferSize(bufferSize);
+    }
+
+    public final void setSendBufferSize(int bufferSize) {
+        conn.setSendBufferSize(bufferSize);
+    }
+
+    public final void setTranscoderBufferSize(int transcoderBufferSize) {
+        this.transcoderBufferSize = transcoderBufferSize;
+    }
+
+    public final int getNumberOfFilesToSend() {
+        return files.size();
+    }
+
+    public final int getNumberOfFilesSent() {
+        return filesSent;
+    }
+
+    public final long getTotalSizeSent() {
+        return totalSize;
+    }
+
+    public List<FileInfo> getFileInfos() {
+        return files;
+    }
+
+
+    private static void promptStgCmt(DicomObject cmtrslt, float seconds) {
+        
+        DicomElement refSOPSq = cmtrslt.get(Tag.ReferencedSOPSequence);
+        System.out.print(refSOPSq.countItems());
+        System.out.println(" successful");
+        DicomElement failedSOPSq = cmtrslt.get(Tag.FailedSOPSequence);
+        if (failedSOPSq != null) {
+            System.out.print(failedSOPSq.countItems());
+            System.out.println(" FAILED!");
+        }
+    }
+
+    private synchronized DicomObject waitForStgCmtResult() throws InterruptedException {
+        while (stgCmtResult == null) wait();
+        return stgCmtResult;
+    }
+
+    private static void prompt(DcmSndV2 dcmsnd, float seconds) {
+        System.out.print("\nSent ");
+        System.out.print(dcmsnd.getNumberOfFilesSent());
+        System.out.print(" objects (=");
+        promptBytes(dcmsnd.getTotalSizeSent());
+        System.out.print(") in ");
+        System.out.print(seconds);
+        System.out.print("s (=");
+        promptBytes(dcmsnd.getTotalSizeSent() / seconds);
+        System.out.println("/s)");
+    }
+
+    private static void promptBytes(float totalSizeSent) {
+        if (totalSizeSent > MB) {
+            System.out.print(totalSizeSent / MB);
+            System.out.print("MB");
+        } else {
+            System.out.print(totalSizeSent / KB);
+            System.out.print("KB");
+        }
+    }
+
+    private static int toPort(String port) {
+        return port != null ? parseInt(port, "illegal port number", 1, 0xffff)
+                : 104;
+    }
+
+    private static String[] split(String s, char delim) {
+        String[] s2 = { s, null };
+        int pos = s.indexOf(delim);
+        if (pos != -1) {
+            s2[0] = s.substring(0, pos);
+            s2[1] = s.substring(pos + 1);
+        }
+        return s2;
+    }
+
+    private static void exit(String msg) {
+        System.err.println(msg);
+        System.err.println("Try 'dcmsnd -h' for more information.");
+        System.exit(1);
+    }
+
+    private static int parseInt(String s, String errPrompt, int min, int max) {
+        try {
+            int i = Integer.parseInt(s);
+            if (i >= min && i <= max)
+                return i;
+        } catch (NumberFormatException e) {
+            // parameter is not a valid integer; fall through to exit
+        }
+        exit(errPrompt);
+        throw new RuntimeException();
+    }
+
+    public synchronized void addFile(ByteBuffer bb) {
+      
+        FileInfo info = new FileInfo(bb);
+        InputStream inStream = info.getInputStream();
+        DicomObject dcmObj = new BasicDicomObject();
+        DicomInputStream in = null;
+        try {
+            in = new DicomInputStream(inStream);
+            in.setHandler(new StopTagInputHandler(Tag.StudyDate));
+            in.readDicomObject(dcmObj, PEEK_LEN);
+            info.tsuid = in.getTransferSyntax().uid();
+            info.fmiEndPos = in.getEndOfFileMetaInfoPosition();
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.err.println("WARNING: Failed to parse - skipped.");
+            System.out.print('F');
+            return;
+        } finally {
+            CloseUtils.safeClose(in);
+        }
+               
+        info.cuid = dcmObj.getString(Tag.SOPClassUID);
+        if (info.cuid == null) {
+            System.err.println("WARNING: Missing SOP Class UID in  - skipped.");
+            System.out.print('F');
+            return;
+        }
+        info.iuid = dcmObj.getString(Tag.SOPInstanceUID);
+        if (info.iuid == null) {
+            System.err.println("WARNING: Missing SOP Instance UID in  - skipped.");
+            System.out.print('F');
+            return;
+        }
+        
+        addTransferCapability(info.cuid, info.tsuid);
+        files.add(info);
+        System.out.print('.');
+    }
+
+    public void addTransferCapability(String cuid, String tsuid) {
+        Set<String> ts = as2ts.get(cuid);
+        if (fileref) {
+            if (ts == null) {
+                as2ts.put(cuid,
+                        Collections.singleton(DCM4CHEE_URI_REFERENCED_TS_UID));
+            }
+        } else {
+            if (ts == null) {
+                ts = new HashSet<String>();
+                ts.add(UID.ImplicitVRLittleEndian);
+                as2ts.put(cuid, ts);
+            }
+            ts.add(tsuid);
+        }
+    }
+    
+
+
+    public void configureTransferCapability() {
+        int off = stgcmt || remoteStgcmtAE != null ? 1 : 0;
+        TransferCapability[] tc = new TransferCapability[off + as2ts.size()];
+        if (off > 0) {
+            tc[0] = new TransferCapability(
+                    UID.StorageCommitmentPushModelSOPClass,
+                    ONLY_IVLE_TS,
+                    TransferCapability.SCU);
+        }
+        Iterator<Map.Entry<String, Set<String>>> iter = as2ts.entrySet().iterator();
+        for (int i = off; i < tc.length; i++) {
+            Map.Entry<String, Set<String>> e = iter.next();
+            String cuid = e.getKey();
+            Set<String> ts = e.getValue();
+            tc[i] = new TransferCapability(cuid,
+                    ts.toArray(new String[ts.size()]),
+                    TransferCapability.SCU);
+        }
+        ae.setTransferCapability(tc);
+    }
+
+    public void start() throws IOException {
+        if (conn.isListening()) {
+            conn.bind(executor );
+            System.out.println("Start Server listening on port " + conn.getPort());
+        }
+    }
+
+    public void stop() {
+        if (conn.isListening()) {
+            try {
+                Thread.sleep(shutdownDelay);
+            } catch (InterruptedException e) {
+                // Should not happen
+                e.printStackTrace();
+            }
+            conn.unbind();
+        }
+    }
+
+    public void open() throws IOException, ConfigurationException,
+            InterruptedException {
+        assoc = ae.connect(remoteAE, executor);
+    }
+
+    public void openToStgcmtAE() throws IOException, ConfigurationException,
+            InterruptedException {
+        assoc = ae.connect(remoteStgcmtAE, executor);
+    }
+
+    public void send() {
+        for (int i = 0, n = files.size(); i < n; ++i) {
+            FileInfo info = files.get(i);
+            TransferCapability tc = assoc.getTransferCapabilityAsSCU(info.cuid);
+            if (tc == null) {
+                System.out.println();
+                System.out.println(UIDDictionary.getDictionary().prompt(
+                        info.cuid)
+                        + " not supported by " + remoteAE.getAETitle());
+                System.out.println("skip file " + info.data);
+                continue;
+            }
+            
+            
+            String tsuid = selectTransferSyntax(tc.getTransferSyntax(),
+                    fileref ? DCM4CHEE_URI_REFERENCED_TS_UID : info.tsuid);
+            if (tsuid == null) {
+                System.out.println();
+                System.out.println(UIDDictionary.getDictionary().prompt(
+                        info.cuid)
+                        + " with "
+                        + UIDDictionary.getDictionary().prompt(
+                                fileref ? DCM4CHEE_URI_REFERENCED_TS_UID
+                                        : info.tsuid)
+                        + " not supported by " + remoteAE.getAETitle());
+                System.out.println("skip file " + info.data);
+                continue;
+            }
+
+            try {
+                DimseRSPHandler rspHandler = new DimseRSPHandler() {
+                    @Override
+                    public void onDimseRSP(Association as, DicomObject cmd,
+                            DicomObject data) {
+                        DcmSndV2.this.onDimseRSP(cmd);
+                    }
+                };
+                
+                if(MoveOriginatorMessageID!=null)
+                {
+                    int messageID = Integer.parseInt(MoveOriginatorMessageID);
+                    assoc.cstore(info.cuid, info.iuid, priority, assoc.getCallingAET(), messageID,
+                        new DataWriter(info), tsuid, rspHandler);
+                }
+                else
+                {
+                    assoc.cstore(info.cuid, info.iuid, priority, 
+                        new DataWriter(info), tsuid, rspHandler);
+                }
+                
+                
+                
+                //assoc.cstore(info.cuid, info.iuid, priority, assoc.getCallingAET(), priority, new DataWriter(info), tsuid, rspHandler);
+                
+            } catch (NoPresentationContextException e) {
+                System.err.println("WARNING: " + e.getMessage()
+                        + " - cannot send " + info.data);
+                System.out.print('F');
+            } catch (IOException e) {
+                e.printStackTrace();
+                System.err.println("ERROR: Failed to send - " + info.data + ": "
+                        + e.getMessage());
+                System.out.print('F');
+            } catch (InterruptedException e) {
+                // should not happen
+                e.printStackTrace();
+            }
+        }
+        try {
+            assoc.waitForDimseRSP();
+        } catch (InterruptedException e) {
+            // should not happen
+            e.printStackTrace();
+        }
+        
+        //TODO: PERHAPS CLEAN THE CLASS:
+    }
+
+    public boolean commit() {
+        DicomObject actionInfo = new BasicDicomObject();
+        actionInfo.putString(Tag.TransactionUID, VR.UI, UIDUtils.createUID());
+        
+        DicomElement refSOPSq = actionInfo.putSequence(Tag.ReferencedSOPSequence);
+        for (int i = 0, n = files.size(); i < n; ++i) {
+            FileInfo info = files.get(i);
+            if (info.transferred) {
+                BasicDicomObject refSOP = new BasicDicomObject();
+                
+                refSOP.putString(Tag.ReferencedSOPClassUID, VR.UI, info.cuid);
+                refSOP.putString(Tag.ReferencedSOPInstanceUID, VR.UI, info.iuid);
+
+                refSOPSq.addDicomObject(refSOP);
+            }
+        }
+        try {
+            stgCmtResult = null;
+            DimseRSP rsp = assoc.naction(UID.StorageCommitmentPushModelSOPClass,
+                UID.StorageCommitmentPushModelSOPInstance, STG_CMT_ACTION_TYPE,
+                actionInfo, UID.ImplicitVRLittleEndian);
+            rsp.next();
+            DicomObject cmd = rsp.getCommand();
+            int status = cmd.getInt(Tag.Status);
+            if (status == 0) {
+                return true;
+            }
+            System.err.println(
+                    "WARNING: Storage Commitment request failed with status: "
+                    + StringUtils.shortToHex(status) + "H");
+            System.err.println(cmd.toString());
+        } catch (NoPresentationContextException e) {
+            System.err.println("WARNING: " + e.getMessage()
+                    + " - cannot request Storage Commitment");
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.err.println(
+                    "ERROR: Failed to send Storage Commitment request: "
+                    + e.getMessage());
+        } catch (InterruptedException e) {
+            // should not happen
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    private String selectTransferSyntax(String[] available, String tsuid) {
+        if (tsuid.equals(UID.ImplicitVRLittleEndian))
+            return selectTransferSyntax(available, IVLE_TS);
+        if (tsuid.equals(UID.ExplicitVRLittleEndian))
+            return selectTransferSyntax(available, EVLE_TS);
+        if (tsuid.equals(UID.ExplicitVRBigEndian))
+            return selectTransferSyntax(available, EVBE_TS);
+        for (int j = 0; j < available.length; j++)
+            if (available[j].equals(tsuid))
+                return tsuid;
+        return null;
+    }
+
+    private String selectTransferSyntax(String[] available, String[] tsuids) {
+        for (int i = 0; i < tsuids.length; i++)
+            for (int j = 0; j < available.length; j++)
+                if (available[j].equals(tsuids[i]))
+                    return available[j];
+        return null;
+    }
+
+    public void close() {
+        try {
+            assoc.release(false);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @return the MoveOriginatorMessageID
+     */
+    public String getMoveOriginatorMessageID() {
+        return MoveOriginatorMessageID;
+    }
+
+    /**
+     * @param MoveOriginatorMessageID the MoveOriginatorMessageID to set
+     */
+    public void setMoveOriginatorMessageID(String MoveOriginatorMessageID) {
+        this.MoveOriginatorMessageID = MoveOriginatorMessageID;
+    }
+
+    public static final class FileInfo {
+        ByteBuffer data;
+
+        String cuid;
+
+        String iuid;
+
+        String tsuid;
+
+        long fmiEndPos;
+
+        long length;
+
+        boolean transferred;
+
+        int status;
+
+        public FileInfo(ByteBuffer data) {
+            this.data = data;
+            this.length = data.array().length;
+        }
+
+        public InputStream getInputStream(){
+            ByteArrayInputStream inStream = new ByteArrayInputStream(data.array());
+            BufferedInputStream buff = new BufferedInputStream(inStream);
+            return buff;                   
+    }
+
+    }
+    
+    
+    private class DataWriter implements org.dcm4che2.net.DataWriter {
+
+        private FileInfo info;
+
+        public DataWriter(FileInfo info) {
+            this.info = info;
+        }
+
+        public void writeTo(PDVOutputStream out, String tsuid)
+                throws IOException {
+            if (tsuid.equals(info.tsuid)) {                            
+                InputStream fis = info.getInputStream();
+                try {
+                    long skip = info.fmiEndPos;
+                    while (skip > 0)
+                        skip -= fis.skip(skip);
+                    
+                    out.copyFrom(fis);
+                                       
+                } finally {
+                    fis.close();
+                }
+            } else if (tsuid.equals(DCM4CHEE_URI_REFERENCED_TS_UID)) {
+                
+                DicomObject attrs;                
+                DicomInputStream dis = new DicomInputStream(info.getInputStream());
+                try {
+                    dis.setHandler(new StopTagInputHandler(Tag.PixelData));
+                    attrs = dis.readDicomObject();
+                } finally {
+                    dis.close();
+                }
+                DicomOutputStream dos = new DicomOutputStream(out);
+                attrs.putString(Tag.RetrieveURI, VR.UT, info.toString());
+                dos.writeDataset(attrs, tsuid);
+             } else {
+                DicomInputStream dis = new DicomInputStream(info.getInputStream());
+                try {
+                    DicomOutputStream dos = new DicomOutputStream(out);
+                    dos.setTransferSyntax(tsuid);
+                    TranscoderInputHandler h = new TranscoderInputHandler(dos,
+                            transcoderBufferSize);
+                    dis.setHandler(h);
+                    dis.readDicomObject();
+                } finally {
+                    dis.close();
+                }
+            }
+        }
+
+    }
+
+    private void promptErrRSP(String prefix, int status, FileInfo info,
+            DicomObject cmd) {
+        System.err.println(prefix + StringUtils.shortToHex(status) + "H for "
+                + info.data + ", cuid=" + info.cuid + ", tsuid=" + info.tsuid);
+        System.err.println(cmd.toString());
+    }
+
+    private void onDimseRSP(DicomObject cmd) {
+        int status = cmd.getInt(Tag.Status);
+        int msgId = cmd.getInt(Tag.MessageIDBeingRespondedTo);
+        FileInfo info = files.get(msgId - 1);
+        info.status = status;
+        switch (status) {
+        case 0:
+            info.transferred = true;
+            totalSize += info.length;
+            ++filesSent;
+            System.out.print('.');
+            break;
+        case 0xB000:
+        case 0xB006:
+        case 0xB007:
+            info.transferred = true;
+            totalSize += info.length;
+            ++filesSent;
+            promptErrRSP("WARNING: Received RSP with Status ", status, info,
+                    cmd);
+            System.out.print('W');
+            break;
+        default:
+            promptErrRSP("ERROR: Received RSP with Status ", status, info, cmd);
+            System.out.print('F');
+        }
+    }
+
+    @Override
+    protected synchronized void onNEventReportRSP(Association as, int pcid,
+            DicomObject rq, DicomObject info, DicomObject rsp) {
+        stgCmtResult = info;
+        notifyAll();
+    }
+
+    public void initTLS() throws GeneralSecurityException, IOException {
+        KeyStore keyStore = loadKeyStore(keyStoreURL, keyStorePassword);
+        KeyStore trustStore = loadKeyStore(trustStoreURL, trustStorePassword);
+        device.initTLS(keyStore,
+                keyPassword != null ? keyPassword : keyStorePassword,
+                trustStore);
+    }
+
+    private static KeyStore loadKeyStore(String url, char[] password)
+            throws GeneralSecurityException, IOException {
+        KeyStore key = KeyStore.getInstance(toKeyStoreType(url));
+        InputStream in = openFileOrURL(url);
+        try {
+            key.load(in, password);
+        } finally {
+            in.close();
+        }
+        return key;
+    }
+
+    private static InputStream openFileOrURL(String url) throws IOException {
+        if (url.startsWith("resource:")) {
+            return DcmSndV2.class.getClassLoader().getResourceAsStream(
+                    url.substring(9));
+        }
+        try {
+            return new URL(url).openStream();
+        } catch (MalformedURLException e) {
+            return new FileInputStream(url);
+        }
+    }
+
+    private static String toKeyStoreType(String fname) {
+        return fname.endsWith(".p12") || fname.endsWith(".P12")
+                 ? "PKCS12" : "JKS";
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DicomEchoReply.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DicomEchoReply.java
new file mode 100755
index 0000000..9093345
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/DicomEchoReply.java
@@ -0,0 +1,448 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ *
+ *  Generic DICOM Worklist Server SCP
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+//import configurations.ConfigurationsValues;
+
+//import gui.MainWindow;
+//import gui.MainWindow.LOG_MODES;
+import java.io.IOException;
+import java.util.concurrent.Executor;
+
+
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.ConfigurationException;
+import org.dcm4che2.data.UID;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+import org.dcm4che2.net.NewThreadExecutor;
+import org.dcm4che2.net.TransferCapability;
+import org.dcm4che2.net.UserIdentity;
+import org.dcm4che2.net.service.VerificationService;
+import pt.ua.dicoogle.core.ServerSettings;
+
+/**
+ *
+ * @author Joaoffr  <joaoffr at ua.pt>
+ * @author DavidP   <davidp at ua.pt>
+ *
+ * @version $Revision: 002 $ $Date: 2008-11-22 14:25:00  $
+ * @since Nov 21, 2008
+ *
+ */
+public class DicomEchoReply extends VerificationService {
+
+    
+    /** Settings */         
+    ServerSettings s = ServerSettings.getInstance();
+    
+    private static final String[] TRANSF_CAP = {
+        UID.ImplicitVRLittleEndian,
+        UID.ExplicitVRBigEndian,
+        UID.ExplicitVRLittleEndian
+    };
+
+    /* Implemented SOP Class */
+    private static final String SOP_CLASS = UID.VerificationSOPClass;
+
+    private static final int PORT_OFFSET = 100;
+
+    private static final String SERVICE_LABEL = "";
+
+
+    /**** Class Atributes ****/
+
+    private static final String MODULE_NAME = "DICOMWLS_EchoReply";                     /* DEFAULT Implemented module name */
+    private final NetworkApplicationEntity remoteAE = new NetworkApplicationEntity();   /* Remote Application Entity (client) */
+    private final NetworkConnection remoteConn = new NetworkConnection();               /* Remote connection associated with remoteAE */
+    private final Device device = new Device(MODULE_NAME);                              /* Module device */
+    private final NetworkApplicationEntity localAE = new NetworkApplicationEntity();    /* Local Application Entity (this server) 'ea' */
+    private final NetworkConnection localConn = new NetworkConnection();                /* Local connection associated with localAE 'conn' */
+    private boolean started = false;                                                    /* True if server is allready started */
+    private int port = 0;
+
+
+
+    /* Module executor */
+    private static final Executor executor = (Executor) new NewThreadExecutor(MODULE_NAME);        /* Server thread */
+
+
+
+    public DicomEchoReply() {
+
+        super();
+
+        this.port = s.getWlsPort() + DicomEchoReply.PORT_OFFSET; ;
+        /* clients */
+        this.remoteAE.setInstalled(true);
+        this.remoteAE.setAssociationInitiator(true);
+        this.remoteAE.setNetworkConnection(this.remoteConn);
+        
+
+
+        /* server */
+        this.started = false;
+        this.localAE.setInstalled(true);
+        this.localAE.setAssociationAcceptor(true);
+        this.localAE.setAssociationInitiator(false);
+        this.localAE.setNetworkConnection(this.localConn );
+        this.localAE.setAETitle(s.getAE() + DicomEchoReply.SERVICE_LABEL);
+        this.localAE.register(new VerificationService());
+        this.localAE.register(this);
+
+        TransferCapability[] tc = { new TransferCapability( DicomEchoReply.SOP_CLASS,
+                                                            DicomEchoReply.TRANSF_CAP,
+                                                            TransferCapability.SCP) };
+        this.localAE.setTransferCapability(tc);
+
+/*        this.localAE.setDimseRspTimeout(confs.getWlsConfigs().getDIMSE_RSP_TIMEOUT());
+        this.localAE.setIdleTimeout(confs.getWlsConfigs().getIDLE_TIMEOUT());*/
+
+        /*this.localAE.setMaxPDULengthReceive(confs.getWlsConfigs().getMAX_PDU_LENGTH_RECEIVE());
+        this.localAE.setMaxPDULengthSend(confs.getWlsConfigs().getMAX_PDU_LENGTH_SEND());*/
+        /**
+        this.localAE.setSupportedCharacterSet("CharacterSetSup");*/
+
+        this.localConn.setPort(this.port);
+        //this.localConn.setMaxScpAssociations(confs.getWlsConfigs().getMAX_CLIENT_ASSOCS());
+        /*this.localConn.setHostname(DicomWLS.LOCAL_HOST_NAME);*/
+       // this.localConn.setAcceptTimeout(confs.getWlsConfigs().getACCEPT_TIMEOUT());
+        //this.localConn.setConnectTimeout(confs.getWlsConfigs().getCONNECTION_TIMEOUT());
+
+
+        //this.device.setDescription(confs.getWlsConfigs().getDEVICE_DESCRIPTION());
+        this.device.setNetworkApplicationEntity(this.localAE);
+        this.device.setNetworkConnection(this.localConn);
+        /*this.device.setDeviceName(DicomWLS.MODULE_NAME);*/
+
+    }
+
+
+    /**
+     * Set local Host Name
+     * @param hostname
+     */
+    public final void setLocalHost(String hostname) {
+        this.localConn.setHostname(hostname);
+    }
+
+    /**
+     * Get Local Host Name
+     * @return
+     */
+    public final String getLocalHost() {
+        return this.localConn.getHostname();
+    }
+
+    /**
+     * Set Remote Host Name
+     * @param hostname
+     */
+    public final void setRemoteHost(String hostname) {
+        this.remoteConn.setHostname(hostname);
+    }
+
+    /**
+     * Get Remote Host Name
+     * @return
+     */
+    public final String getRemoteHost() {
+        return this.remoteConn.getHostname();
+    }
+
+    /**
+     * Set Local Port
+     * @param port
+     */
+    public final void setLocalPort(int port) {
+         int tmp = (port >= 1 && port <= 0xffff) ? port : 105;
+         this.localConn.setPort(tmp);
+    }
+
+    /**
+     * Get Local Port
+     * @return
+     */
+    public final int getLocalPort() {
+        return this.localConn.getPort();
+    }
+
+    /**
+     * Set Remote Application Entity Title
+     * @param called
+     */
+    public final void setRemoteAET(String called) {
+        this.remoteAE.setAETitle(called);
+    }
+
+    /**
+     * Get Remote Application Entity Title
+     * @return
+     */
+    public final String getRemoteAET() {
+        return this.remoteAE.getAETitle();
+    }
+
+    /**
+     * Set Local Application Entity Title
+     * @param calling
+     */
+    public final void setLocalAET(String calling) {
+        this.localAE.setAETitle(calling);
+    }
+
+    /**
+     * Get Local Application Entity Title
+     * @return
+     */
+    public final String getLocalAET() {
+        return this.localAE.getAETitle();
+    }
+
+    /**
+     * Set Local User Identity
+     * @param userIdentity
+     */
+    public final void setUserIdentity(UserIdentity userIdentity) {
+        this.localAE.setUserIdentity(userIdentity);
+    }
+
+    /**
+     * Get Local User Identity
+     * @return
+     */
+    public final UserIdentity getUserIdentity() {
+        return this.localAE.getUserIdentity();
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    public void setStarted(boolean started) {
+        this.started = started;
+    }
+
+    /**
+     *
+     * @param connectTimeout
+     */
+    public final void setConnectTimeout(int connectTimeout) {
+        this.localConn.setConnectTimeout(connectTimeout);
+    }
+
+    /**
+     *
+     * @param maxPDULength
+     */
+    public final void setMaxPDULengthReceive(int maxPDULength) {
+        this.localAE.setMaxPDULengthReceive(maxPDULength);
+    }
+
+    /**
+     *
+     * @param maxPDULength
+     */
+    public final void setMaxPDULengthSend(int maxPDULength) {
+        this.localAE.setMaxPDULengthSend(maxPDULength);
+    }
+
+    /**
+     *
+     * @param packPDV
+     */
+    public final void setPackPDV(boolean packPDV) {
+        this.localAE.setPackPDV(packPDV);
+    }
+
+    /**
+     *
+     * @param period
+     */
+    public final void setAssociationReaperPeriod(int period) {
+        this.device.setAssociationReaperPeriod(period);
+    }
+
+    /**
+     *
+     * @param timeout
+     */
+    public final void setDimseRspTimeout(int timeout) {
+        this.localAE.setDimseRspTimeout(timeout);
+    }
+
+    /**
+     *
+     * @param tcpNoDelay
+     */
+    public final void setTcpNoDelay(boolean tcpNoDelay) {
+        this.localConn.setTcpNoDelay(tcpNoDelay);
+    }
+
+    /**
+     *
+     * @param timeout
+     */
+    public final void setAcceptTimeout(int timeout) {
+        this.localConn.setAcceptTimeout(timeout);
+    }
+
+    /**
+     *
+     * @param timeout
+     */
+    public final void setReleaseTimeout(int timeout) {
+        this.localConn.setReleaseTimeout(timeout);
+    }
+
+    /**
+     *
+     * @param timeout
+     */
+    public final void setSocketCloseDelay(int timeout) {
+        this.localConn.setSocketCloseDelay(timeout);
+    }
+
+    /**
+     *
+     * @param bufferSize
+     */
+    public final void setReceiveBufferSize(int bufferSize) {
+        this.localConn.setReceiveBufferSize(bufferSize);
+    }
+
+    /**
+     *
+     * @param bufferSize
+     */
+    public final void setSendBufferSize(int bufferSize) {
+        this.localConn.setSendBufferSize(bufferSize);
+    }
+
+    /**
+     *
+     * @param ts
+     */
+    public void setTransferSyntax(String[] ts) {
+        TransferCapability[] tc = { new TransferCapability(
+                UID.ModalityWorklistInformationModelFIND, ts,
+                TransferCapability.SCU) };
+        this.localAE.setTransferCapability(tc);
+    }
+
+    /**
+     *
+     * @param timeout
+     */
+    public final void setIdleTimeout(int timeout) {
+        this.localAE.setIdleTimeout(timeout);
+    }
+
+
+
+    /**
+     * Start server socket accept client(s) connection
+     *
+     * @return
+     * @throws java.io.IOException
+     * @throws org.dcm4che2.net.ConfigurationException
+     * @throws java.lang.InterruptedException
+     */
+    public boolean startListening() {
+        if (this.device != null) {
+            try {
+                CommandUtils.setIncludeUIDinRSP(true);
+                this.device.startListening(DicomEchoReply.executor);
+            } catch (Exception ex) {
+                 ///MainWindow.getMw().add2ServerLogln(ex.getMessage(), LOG_MODES.ERROR);
+                 return false;
+            }
+            this.started = true;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Stop all active client socket connections
+     *
+     * @return
+     * @throws java.io.IOException
+     * @throws org.dcm4che2.net.ConfigurationException
+     * @throws java.lang.InterruptedException
+     */
+    public boolean stopListening() {
+        if (this.device != null) {
+            this.device.stopListening();
+            this.started = false;
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return( "[START INFO PRINT]" + "\n" +
+                    "\tModuleName = " + DicomEchoReply.MODULE_NAME + "\n" +
+                    "\tLocalAETitle = " + this.localAE.getAETitle() + "\n" +
+                    "\tPort = " + this.localConn.getPort() + "\n" +
+                    "\tTransfereCapabilities = " + strVectConcat(this.localAE.getTransferCapability()[0].getTransferSyntax(), "; ") + "\n" +
+                    "\tModality = " + DicomEchoReply.SOP_CLASS + "\n" +
+                    "\tStarted = " + this.started + "\n" +
+                "[END INFO PRINT]" + "\n"
+              );
+    }
+
+    @Override
+    public void cecho(Association as, int pcid, DicomObject cmd) throws IOException {
+        ///MainWindow.getMw().add2ServerLogln("CEcho request from " + as.getRemoteAET() + " received!", LOG_MODES.INFO);
+
+        super.cecho(as, pcid, cmd);
+
+        //System.out.println(cmd);
+
+        ///MainWindow.getMw().add2ServerLogln("CEcho response send to " + as.getRemoteAET() + "!", LOG_MODES.INFO);
+
+    }
+    
+
+    private static String strVectConcat(String[] stVectIN, String sep) {
+
+        if (stVectIN == null) return new String("[any]");
+
+        String temp = new String("");
+        for (int i = 0; i < stVectIN.length - 1; i++)
+            temp = temp + stVectIN[i] + sep;
+
+        temp = temp + stVectIN[stVectIN.length - 1];
+
+        return temp;
+    }
+
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/EchoReplyService.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/EchoReplyService.java
new file mode 100755
index 0000000..c06875a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/EchoReplyService.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * Thread for DICOM Echo Reply service implementation
+ */
+
+package pt.ua.dicoogle.server.queryretrieve;
+
+
+/**
+ *
+ * @author Joaoffr  <joaoffr at ua.pt>
+ * @author DavidP   <davidp at ua.pt>
+ *
+ * @version $Revision: 002 $ $Date: 2008-11-22 14:25:00  $
+ * @since Nov 21, 2008
+ *
+ */
+public class EchoReplyService extends Thread 
+{
+
+    private DicomEchoReply echoReply = null;
+
+
+    public EchoReplyService() {
+        this.echoReply = new DicomEchoReply();
+    }
+
+
+
+    public DicomEchoReply getEchoReply() {
+        return echoReply;
+    }
+
+
+
+    @Override
+    public void run() {
+        /* 
+         * ////
+        try {
+            this.mw.add2ServerLogln("Starting Verification Service...", MainWindow.LOG_MODES.WARNING);
+            
+            if (this.echoReply.startListening()) {
+                this.mw.add2ServerLogln("Verification Service start listening on port "+ this.echoReply.getLocalPort() + ".",
+                                        MainWindow.LOG_MODES.NORMAL);
+
+                this.mw.add2ServerLogln("Verification Service started!",MainWindow.LOG_MODES.WARNING);
+            } else {
+                this.mw.add2ServerLogln("Error Starting Verification Service on port " + this.echoReply.getLocalPort() + "...",
+                                        MainWindow.LOG_MODES.ERROR);
+            }
+        }
+        catch (Exception ex) {
+            this.mw.add2ServerLogln(ex.getMessage(), MainWindow.LOG_MODES.ERROR);
+        }
+        
+        */
+    }
+
+    public void  stopService() {
+        /* ///
+        try {
+            this.mw.add2ServerLogln("Stopping Verification Service...", MainWindow.LOG_MODES.WARNING);
+
+            if (this.echoReply.stopListening()) {
+                super.stop();
+
+                this.mw.add2ServerLogln("Verification Service stoped.", MainWindow.LOG_MODES.WARNING);
+            } else {
+                this.mw.add2ServerLogln("Error stopping Verification Service on port " + this.echoReply.getLocalPort() + " ...",
+                                        MainWindow.LOG_MODES.ERROR);
+            }
+        }
+        catch (Exception ex) {
+            this.mw.add2ServerLogln(ex.getMessage(), MainWindow.LOG_MODES.ERROR);
+        }
+         */
+        
+    }
+
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/Filter.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/Filter.java
new file mode 100755
index 0000000..d540128
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/Filter.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * DICOM Objects filter
+ */
+
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.util.Iterator;
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+
+/**
+ *
+ * @author Joaoffr  <joaoffr at ua.pt>
+ * @author DavidP   <davidp at ua.pt>
+ *
+ * @version $Revision: 002 $ $Date: 2008-11-22 14:25:00  $
+ * @since Nov 21, 2008
+ *
+ */
+public class Filter {
+
+     public static boolean applyFilter(DicomObject keyObj, DicomObject sourceObj)
+     {
+        DicomObject kObj = keyObj;
+        DicomObject sObj = sourceObj;
+
+        Iterator<DicomElement> itKeys = kObj.datasetIterator();
+
+        DicomElement dcmElmt;
+        int tag;
+
+        //DebugManager.getInstance().debug("Appling a filter to DCMObj");
+
+        for (; itKeys.hasNext();  ) {
+            dcmElmt = (DicomElement) itKeys.next();
+
+            if (dcmElmt.isEmpty()) {
+                continue;
+            }
+
+            if (dcmElmt.hasDicomObjects()) {
+                if (dcmElmt.getDicomObject() == null) continue;
+
+                if (!applyFilter(dcmElmt.getDicomObject(), sObj)) {
+                    return false;
+                }
+                continue;
+            }
+
+             tag = dcmElmt.tag();
+
+             if ( sObj.get(tag)!= null &&
+                  kObj.get(tag)!= null &&
+                  !(byte2string(sObj.get(tag).getBytes()).trim().equals(byte2string(dcmElmt.getBytes()).trim()))
+                 ) {
+                    //System.out.println("-->" + byte2string(sObj.get(tag).getBytes()) );
+                    return false;
+             }
+        }
+
+        return true;
+    }
+
+
+     private static String byte2string(byte[] in) {
+        String out = "";
+
+        for (int i = 0; i < in.length; i++) {
+            out += (char)in[i];
+        }
+
+        return out;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/FindRSP.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/FindRSP.java
new file mode 100755
index 0000000..db9ccf6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/FindRSP.java
@@ -0,0 +1,331 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * 
+ * The Goal of this class is based on DicomObject 
+ * send FindRSP to destination entity 
+ * 
+ * It will search data at Index of Lucene 
+ * 
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import aclmanager.core.LuceneQueryACLManager;
+import aclmanager.models.Principal;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.dcm4che2.data.DicomElement;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.VR;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.Status;
+
+
+import pt.ua.dicoogle.core.exceptions.CFindNotSupportedException;
+import pt.ua.dicoogle.server.SearchDicomResult;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class FindRSP implements DimseRSP 
+{
+    
+    private DicomObject rsp;
+    private DicomObject keys;
+    
+    
+    
+    /** 
+     * Each moment in timeline we're getting a item
+     */
+    private DicomObject mwl = null;
+
+    SearchDicomResult search = null ; 
+    
+    private String callingAET;
+    private LuceneQueryACLManager luke;
+    
+    public FindRSP(DicomObject keys, DicomObject rsp, String callingAET, LuceneQueryACLManager luke)
+    {
+        this.rsp = rsp ; 
+        this.keys = keys ;
+        
+        this.callingAET = callingAET;
+        this.luke = luke;
+        
+        
+        /** Debug - show keys, rsp, index */ 
+        if (keys!=null)
+        {
+            //DebugManager.getInstance().debug("keys object: ");
+            //DebugManager.getInstance().debug(keys.toString());
+        }
+        if (rsp!=null)
+        {
+            //DebugManager.getInstance().debug("Rsp object");
+            //DebugManager.getInstance().debug(rsp.toString());
+        }
+        
+        /** 
+         * Get object to search
+         */
+        ArrayList<String> extrafields  = null ;
+        extrafields = new ArrayList<String>();
+
+        extrafields.add("PatientName");
+        extrafields.add("PatientSex");
+        extrafields.add("PatientID");
+        extrafields.add("Modality");
+        extrafields.add("StudyDate");
+        extrafields.add("StudyTime");
+        extrafields.add("AccessionNumber");
+        extrafields.add("StudyID");
+        extrafields.add("StudyDescription");
+        extrafields.add("SeriesNumber");
+        extrafields.add("SeriesInstanceUID");
+        extrafields.add("SeriesDescription");
+        extrafields.add("ReferringPhysicianName");
+        extrafields.add("PatientBirthDate");
+        extrafields.add("ModalitiesInStudy");
+        extrafields.add("StudyInstanceUID");
+        extrafields.add("InstitutionName");
+        extrafields.add("AcquisitionDeviceProcessingDescription");
+        extrafields.add("ProtocolName");
+
+        extrafields.add("SeriesDate");
+
+        extrafields.add("OperatorsName");
+        extrafields.add("RequestingPhysician");
+        extrafields.add("BodyPartThickness");
+        extrafields.add("PatientOrientation");
+        extrafields.add("CompressionForce");
+
+        extrafields.add("ViewPosition");
+        extrafields.add("ImageLaterality");
+        extrafields.add("AcquisitionDeviceProcessingDescription");
+
+
+        extrafields.add("ViewCodeSequence_CodeValue");
+        extrafields.add("ViewCodeSequence_CodingSchemeDesignator");
+        extrafields.add("ViewCodeSequence_CodingSchemeVersion");
+        extrafields.add("ViewCodeSequence_CodeMeaning");
+
+
+        extrafields.add("SOPInstanceUID");
+        
+        String query = getQueryString(keys, rsp);
+        //System.out.println("OLD Query: "+query);
+        query = applyQueryFilter(query);
+        
+        System.out.println("NEW Query: "+query);
+
+        /** 
+         * Search results
+         * TODO: 
+         * - Get Search String Query?
+         * - Is A Network Search?
+         * - How works extrafields?
+         */
+
+        SearchDicomResult.QUERYLEVEL level = null ;
+        /*
+        if (CFindBuilder.isPatientRoot(rsp))
+        {
+            level = SearchDicomResult.QUERYLEVEL.PATIENT;
+        }
+        else if (CFindBuilder.isStudyRoot(rsp))
+        {
+            level = SearchDicomResult.QUERYLEVEL.STUDY;
+        }*/
+        DicomElement elem = keys.get(Integer.parseInt("00080052", 16));
+        String levelStr = new String(elem.getBytes());
+
+        if (levelStr.contains("PATIENT"))
+        {
+            level = SearchDicomResult.QUERYLEVEL.PATIENT;
+        }
+        else if(levelStr.contains("STUDY"))
+        {
+            level = SearchDicomResult.QUERYLEVEL.STUDY;
+        }
+        else if (levelStr.contains("SERIES"))
+        {
+            level = SearchDicomResult.QUERYLEVEL.SERIE;
+        }
+        else if (levelStr.contains("IMAGE"))
+        {
+            level = SearchDicomResult.QUERYLEVEL.IMAGE;
+        }
+        System.out.println("Charset: "+ this.keys.get(Tag.SpecificCharacterSet));
+        search = new SearchDicomResult(query,
+                 true, extrafields, level);
+
+
+
+         if (search == null)
+         {
+            //DebugManager.getInstance().debug(">> Search is null, so" +
+            //        " somethig is wrong ");
+         }
+         
+        // always return Specific Character Set
+        if (!keys.contains(Tag.SpecificCharacterSet)) {
+            this.keys.putNull(Tag.SpecificCharacterSet, VR.CS);
+            keys.putNull(Tag.SpecificCharacterSet, VR.CS);
+            this.rsp.putNull(Tag.SpecificCharacterSet, VR.CS);
+        }
+
+    }
+
+
+
+
+    private String getQueryString(DicomObject keys, DicomObject rsp)
+    {
+        String result = "";
+        try
+        {
+            CFindBuilder c = new CFindBuilder(keys, rsp);
+            result = c.getQueryString() ;
+        } catch (CFindNotSupportedException ex)
+        {
+            LoggerFactory.getLogger(FindRSP.class).error(ex.getMessage(), ex);
+        }
+
+        return result ;
+    }
+
+     private String applyQueryFilter(String normalQuery){
+        if(luke == null)
+            return normalQuery;
+       //LuceneQueryACLManager luke = new LuceneQueryACLManager(manager);
+       
+       String query = luke.produceQueryFilter(new Principal("AETitle", callingAET));
+         if(query.length() > 0 )
+             return normalQuery + query;
+               
+        return normalQuery;
+    }
+
+
+
+    /**
+     * 
+     * Verify if have a next DicomObject and set 
+     * the pointer of DicomObject with correct paraments
+     * It also apply the filter to verify if the DicomObject matches
+     * with query and if it is not search for the next DicomObject.
+     * 
+     * @return true if there is a next DicomObject
+     * @throws java.io.IOException
+     * @throws java.lang.InterruptedException
+     */
+
+    @Override
+    public boolean next() throws IOException, InterruptedException 
+    {
+        if (search!=null)
+        {
+            if (search.hasNext())
+            {
+                    //DebugManager.getInstance().debug("We have next, so get it");
+                    mwl = search.next();
+                    //if (mwl.matches(this.keys, true))
+                    //{
+
+                        // always return Specific Character Set
+                        if (!this.mwl.contains(Tag.SpecificCharacterSet))
+                            this.mwl.putNull(Tag.SpecificCharacterSet, VR.CS);
+                        this.rsp.putInt(Tag.Status, VR.US, mwl.containsAll(keys) ? Status.Pending : Status.PendingWarning);
+                        return true;
+                    //}
+            }
+
+            /** Sucess */
+            this.rsp.putInt(Tag.Status, VR.US, Status.Success);
+            /** Clean pointers */
+            this.mwl = null;
+            this.search = null;
+            return true ;
+            
+        }
+        else
+        {
+            this.rsp.putInt(Tag.Status, VR.US, Status.Cancel);
+        }
+        return false;
+    }
+    
+    /**
+     * 
+     * @return
+     */
+    @Override
+    public DicomObject getCommand() 
+    {
+        return this.rsp;
+    }
+    
+    
+    /**
+     * This method see the current DicomObject and return it
+     * @return null or DicomObject
+     */
+    @Override
+    public DicomObject getDataset() 
+    {
+        //DebugManager.getInstance().debug("Get Data Set");
+        return  this.mwl != null ? this.mwl.subSet(this.keys) : null;
+    }
+
+    @Override
+    public void cancel(Association arg0) throws IOException 
+    {
+
+        search = null ;
+        try
+        {
+            arg0.release(true);
+            
+        } catch (InterruptedException ex)
+        {
+            LoggerFactory.getLogger(FindRSP.class).error(ex.getMessage(), ex);
+        }
+    }
+
+   @Override
+    protected void finalize() throws Throwable
+   {
+
+        super.finalize();
+
+
+    }
+
+}
+    
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/MoveRSP.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/MoveRSP.java
new file mode 100755
index 0000000..93ba9bd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/MoveRSP.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+import java.io.IOException;
+
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.data.Tag;
+import org.dcm4che2.data.VR;
+import org.dcm4che2.net.Association;
+import org.dcm4che2.net.DimseRSP;
+import org.dcm4che2.net.Status;
+
+
+import pt.ua.dicoogle.server.SearchDicomResult;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class MoveRSP  implements DimseRSP 
+{
+    DicomObject rsp = null ;
+    DicomObject keys = null ;
+
+    DicomObject current = null ;
+    SearchDicomResult search = null ; 
+
+
+    public MoveRSP(DicomObject keys, DicomObject rsp)
+    {
+        /* Save args */
+        this.rsp = rsp ;
+        this.keys = keys ;
+        this.current = rsp ; 
+        
+
+       // DebugManager.getInstance().debug("--> Creating MoveRSP");
+        
+
+
+        /** Debug - show keys, rsp, index */
+        if (keys!=null)
+        {
+            //DebugManager.getInstance().debug("keys object: ");
+            //DebugManager.getInstance().debug(keys.toString());
+        }
+        if (rsp!=null)
+        {
+            //DebugManager.getInstance().debug("Rsp object");
+            //DebugManager.getInstance().debug(rsp.toString());
+        }
+
+          this.rsp.putInt(Tag.Status, VR.US, Status.Success);
+            
+    }
+
+    @Override
+    public boolean next() throws IOException, InterruptedException
+    {
+  
+            /** Sucess */
+            this.rsp.putInt(Tag.Status, VR.US, Status.Success);
+            /** Clean pointers */
+            this.current = null;
+            return true ;
+
+    }
+
+    @Override
+    public DicomObject getCommand()
+    {
+        return this.rsp ; 
+    }
+
+    @Override
+    public DicomObject getDataset()
+    {
+         return  this.current != null ? this.current.subSet(this.keys) : null;
+    }
+
+    @Override
+    public void cancel(Association arg0) throws IOException
+    {
+        // TODO
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/QueryRetrieve.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/QueryRetrieve.java
new file mode 100755
index 0000000..1dd7941
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/queryretrieve/QueryRetrieve.java
@@ -0,0 +1,214 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.queryretrieve;
+
+
+import aclmanager.core.ACLManagerInterface;
+import aclmanager.core.ACLXMLParser;
+import aclmanager.core.LuceneQueryACLManager;
+import aclmanager.exceptions.CannotParseFileException;
+
+import java.io.File;
+import java.util.concurrent.Executor;
+
+import pt.ua.dicoogle.core.ServerSettings;
+
+import org.dcm4che2.data.UID;
+import org.dcm4che2.net.CommandUtils;
+import org.dcm4che2.net.Device;
+import org.dcm4che2.net.NetworkApplicationEntity;
+import org.dcm4che2.net.NetworkConnection;
+import org.dcm4che2.net.NewThreadExecutor;
+import org.dcm4che2.net.TransferCapability;
+import org.dcm4che2.net.service.VerificationService;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+import pt.ua.dicoogle.server.DicomNetwork;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class QueryRetrieve extends DicomNetwork 
+{
+
+    /**** Class Atributes ****/
+    
+
+    ServerSettings s  = ServerSettings.getInstance();
+
+    /* Implemented SOP Class */
+    private String sopClass = null;
+
+    private EchoReplyService verifService = null;
+
+    /* DEFAULT Implemented module name */
+    private static final String MODULE_NAME = "DICOOGLE-STORAGE";
+    /* Remote Application Entity (client) */
+    private final NetworkApplicationEntity remoteAE = new NetworkApplicationEntity();
+    /* Remote connection associated with remoteAE */
+    private final NetworkConnection remoteConn = new NetworkConnection();
+    /* Module device */
+    private final Device device = new Device(MODULE_NAME);
+    /* Local Application Entity (this server) 'ea' */
+    private final NetworkApplicationEntity localAE = new NetworkApplicationEntity();
+    /* Local connection associated with localAE 'conn' */
+    private final NetworkConnection localConn = new NetworkConnection();
+    /* True if server is allready started */
+    private boolean started = false;
+    /* True if server is allready started as a Windows Service*/
+    private boolean startedAsService = false;
+    /* Response (to clients) delay (in milisec) */
+    private int rspdelay = 0;                                                           
+
+
+    /* Module executor  -  Server thread */
+    private static Executor executor =  new NewThreadExecutor(MODULE_NAME);        
+
+    private String[] transfCap = ServerSettings.getInstance().getTransfCap().split("[|]");
+    private TransferCapability[] tc = new TransferCapability[5];
+
+    private static String[] multiSop = {UID.StudyRootQueryRetrieveInformationModelFIND,
+                                
+                                UID.PatientRootQueryRetrieveInformationModelFIND
+                                };
+
+    private static String[] moveSop = {UID.StudyRootQueryRetrieveInformationModelMOVE,
+    UID.PatientRootQueryRetrieveInformationModelMOVE};
+    
+    private LuceneQueryACLManager luke;
+  
+    public QueryRetrieve()
+    {
+
+        super("DICOOGLE-QUERYRETRIEVE");
+
+        // super(multiSop, executor);
+                this.sopClass = s.getSOPClass();
+
+
+        //DebugManager.getInstance().debug("SOP Class: ");
+        //DebugManager.getInstance().debug(s.getSOPClass());
+
+        for (String s : transfCap)
+        {
+            //DebugManager.getInstance().debug("TransCap : " + s );
+        }
+
+        tc[0] = new TransferCapability(
+                                        UID.StudyRootQueryRetrieveInformationModelFIND,
+                                        this.transfCap,
+                                        TransferCapability.SCP
+                                      );
+        tc[1] = new TransferCapability(
+                                        UID.StudyRootQueryRetrieveInformationModelMOVE,
+                                        this.transfCap,
+                                        TransferCapability.SCP
+                                      );
+
+        tc[2] = new TransferCapability(
+                                UID.PatientRootQueryRetrieveInformationModelFIND,
+                                this.transfCap,
+                                TransferCapability.SCP
+        );
+        tc[3] = new TransferCapability(
+                        UID.PatientRootQueryRetrieveInformationModelMOVE,
+                        this.transfCap,
+                        TransferCapability.SCP
+        );
+        String [] Verification = {UID.ImplicitVRLittleEndian, UID.ExplicitVRLittleEndian, UID.ExplicitVRBigEndian};
+        tc[4] = new TransferCapability(UID.VerificationSOPClass, Verification, TransferCapability.SCP);
+
+        this.verifService = null;
+        /* server */
+        this.started = false;
+        this.startedAsService = false;
+        this.rspdelay = s.getRspDelay();
+        this.localAE.setInstalled(true);
+        this.localAE.setAssociationAcceptor(true);
+        this.localAE.setAssociationInitiator(false);
+        this.localAE.setNetworkConnection(this.localConn );
+        this.localAE.setAETitle(s.getAE());
+        this.localAE.setTransferCapability(tc);
+        this.localAE.setDimseRspTimeout(s.getDIMSERspTimeout());
+        this.localAE.setIdleTimeout(s.getIdleTimeout());
+        this.localAE.setMaxPDULengthReceive(s.getMaxPDULengthReceive()+1000);
+        this.localAE.setMaxPDULengthSend(s.getMaxPDULenghtSend()+1000);
+
+        try {//TODO: HERE IIII XD
+            File xmlFile = new File(Platform.homePath() + ServerSettings.getInstance().getAccessListFileName());
+            
+            if(xmlFile.exists()){
+                ACLManagerInterface manager = ACLXMLParser.parseFromFile(xmlFile);
+                this.luke = new LuceneQueryACLManager(manager);
+            }
+        } catch (CannotParseFileException ex) {
+            LoggerFactory.getLogger(CFindServiceSCP.class).error(ex.getMessage(), ex);
+        }        
+        
+        this.localAE.register(new CMoveServiceSCP(moveSop, executor, luke));
+        this.localAE.register(new CFindServiceSCP(multiSop, executor, luke));
+        this.localAE.register(new VerificationService());
+
+        this.localConn.setPort(s.getWlsPort());
+        this.localConn.setMaxScpAssociations(s.getMaxClientAssoc());
+        this.localConn.setAcceptTimeout(s.getAcceptTimeout());
+        this.localConn.setConnectTimeout(s.getConnectionTimeout());
+
+        this.device.setDescription(s.getDeviceDescription());
+        this.device.setNetworkApplicationEntity(this.localAE);
+        this.device.setNetworkConnection(this.localConn);        
+    }
+
+
+
+    @Override
+    public boolean doStartService() {
+
+
+        if (this.device != null) 
+        {
+            this.verifService = new EchoReplyService();
+            CommandUtils.setIncludeUIDinRSP(true);
+           
+            try {
+                this.device.startListening(QueryRetrieve.executor);
+                this.verifService.start();
+            } catch (Exception ex) {
+            ex.printStackTrace();
+                 //MainWindow.getMw().add2ServerLogln(ex.getMessage(), LOG_MODES.ERROR);
+                 return false;
+            }
+            this.started = true;
+            //DebugManager.getInstance().debug("Starting server " +
+             //       "- cmove server was started right now .. ");
+                this.startedAsService = true;
+            return true;
+        }
+        return false ;
+    }
+
+    @Override
+    public boolean doStopService() {
+        this.device.stopListening();
+        return true ;
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/HashService.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/HashService.java
new file mode 100755
index 0000000..318b636
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/HashService.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import sun.misc.BASE64Encoder;
+
+/**
+ * This class provides hashing service to passwords with SHA-1 algoritm
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class HashService {
+    /**
+     * Encrypt one password with SHA-1 algorithm
+     *
+     * @param plaintext
+     * @return the hash of the password
+     */
+    public static String getSHA1Hash(String plaintext) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("SHA-1");
+            md.update(plaintext.getBytes("UTF-8"));
+            byte[] raw = md.digest();
+
+            String hash = (new BASE64Encoder()).encode(raw);
+            return hash;
+            
+        } catch (UnsupportedEncodingException ex) {
+            LoggerFactory.getLogger(HashService.class).error(ex.getMessage(), ex);
+        } catch (NoSuchAlgorithmException ex) {
+            LoggerFactory.getLogger(HashService.class).error(ex.getMessage(), ex);
+        }
+
+        return null;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/Role.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/Role.java
new file mode 100644
index 0000000..cf5fe30
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/Role.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public class Role {
+
+
+    private String name;
+    public Role(String name)
+    {
+        this.name = name;
+
+    }
+
+
+    @Override
+    public String toString() {
+        return "Role{" +
+                "name='" + name + '\'' +
+                '}';
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Role role = (Role) o;
+
+        return !(name != null ? !name.equals(role.name) : role.name != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RoleManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RoleManager.java
new file mode 100644
index 0000000..db28eef
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RoleManager.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public interface RoleManager {
+
+    public boolean hasRole(User user, Role r);
+    public Collection<Role> getRoles();
+    public void addRole(Role r);
+    public Role getRole(String name);
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesStruct.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesStruct.java
new file mode 100644
index 0000000..3b4a3dc
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesStruct.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.util.*;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public class RolesStruct implements RoleManager{
+
+    private static RolesStruct instance = null ;
+
+    private Set<Role> roles = new HashSet<>();
+    private Map<String, Role> rolesMap = new HashMap<String, Role>();
+
+    public static synchronized RolesStruct getInstance() {
+        if (instance == null) {
+            instance = new RolesStruct();
+        }
+
+        return instance;
+    }
+    private RolesStruct(){
+        reset();
+    }
+
+    public void reset(){
+        roles = new HashSet<>();
+    }
+
+    @Override
+    public boolean hasRole(User user, Role r) {
+        if (user==null||r==null)
+            return false;
+        return UsersStruct.getInstance().getUser(user.getUsername()).hasRole(r);
+    }
+
+    @Override
+    public Set<Role> getRoles() {
+        return this.roles;
+    }
+
+    @Override
+    public void addRole(Role r) {
+        this.roles.add(r);
+        this.rolesMap.put(r.getName(), r);
+
+    }
+
+    @Override
+    public Role getRole(String name) {
+
+        return this.rolesMap.get(name);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesXML.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesXML.java
new file mode 100755
index 0000000..efdb357
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/RolesXML.java
@@ -0,0 +1,243 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import org.slf4j.LoggerFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import javax.crypto.Cipher;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import java.io.*;
+import java.util.Iterator;
+
+/**
+ * This class saves the list of roles to XML
+ *
+ * @author Luís Bastião Silva <bastiao at bmd-software.com>
+ */
+public class RolesXML extends DefaultHandler
+{
+    private RolesStruct roles = RolesStruct.getInstance();
+    private boolean isRoles = false ;
+
+    private String rolename;
+
+
+
+    public RolesXML()
+    {
+        rolename = "";
+    }
+
+
+    @Override
+    public void startElement( String uri, String localName, String qName,
+            Attributes attribs )
+    {
+
+
+
+        if (localName.equals("Roles"))
+        {
+            isRoles = true ;
+        }
+        else if (this.isRoles && localName.equals("role"))
+        {
+            this.rolename = this.resolveAttrib("name", attribs, "xp");
+        }
+        
+    }
+
+
+    @Override
+    public void endElement( String uri, String localName, String qName )
+    {
+
+        if (localName.equals("Users"))
+        {
+            isRoles = false ;
+        }
+        else if( localName.equals( "role" ) )
+        {
+            roles.addRole(new Role(rolename));
+        }
+        
+    }
+
+     private String resolveAttrib( String attr, Attributes attribs, String defaultValue) {
+         String tmp = attribs.getValue(attr);
+         return (tmp!=null)?(tmp):(defaultValue);
+     }
+
+
+    public RolesStruct getXML()
+    {
+        roles.reset();
+        
+        try
+        {
+
+            FileInputStream fin = new FileInputStream("roles.xml");
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            byte[] data = new byte[1024];
+            int bytesRead;
+
+            while ((bytesRead = fin.read(data)) != -1) {
+                out.write(data, 0, bytesRead);
+                out.flush();
+            }
+
+            byte[] xml = out.toByteArray();
+            
+            if (xml == null)
+            {
+
+                printXML();
+                return roles;
+            }
+
+
+            // Never throws the exception cause file not exists so need try catch
+            InputSource src = new InputSource( new ByteArrayInputStream(xml) );
+            XMLReader r = XMLReaderFactory.createXMLReader();
+            r.setContentHandler(this);
+            r.parse(src);
+            return roles;
+        }
+        catch (SAXException | IOException ex)
+        {
+            LoggerFactory.getLogger(RolesXML.class).error(ex.getMessage(), ex);
+        }
+        return null;
+    }
+
+    /**
+     * Print the roles information to the XML file
+     */
+    public void printXML()
+    {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+       
+
+        PrintWriter pw = new PrintWriter(out);
+        StreamResult streamResult = new StreamResult(pw);
+        SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+
+        TransformerHandler hd = null;
+        try
+        {
+            hd = tf.newTransformerHandler();
+        } catch (TransformerConfigurationException ex)
+        {
+            LoggerFactory.getLogger(RolesXML.class).error(ex.getMessage(), ex);
+        }
+        
+        Transformer serializer = hd.getTransformer();
+        serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+        serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");   
+        try
+        {
+            hd.setResult(streamResult);
+            hd.startDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(RolesXML.class).error(ex.getMessage(), ex);
+        }
+
+        AttributesImpl atts = new AttributesImpl();
+        try
+        {
+            //root element
+            hd.startElement("", "", "Roles", atts);
+
+            Iterator<Role> us = RolesStruct.getInstance().getRoles().iterator();
+
+            atts.clear();
+            while (us.hasNext())
+            {
+                Role role = us.next();
+                
+                atts.addAttribute("", "", "name", "", role.getName());
+
+                hd.startElement("", "", "role", atts);
+                atts.clear();
+                hd.endElement("", "", "role");
+            }
+            hd.endElement("", "", "Roles");
+
+
+            hd.endDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(RolesXML.class).error(ex.getMessage(), ex);
+        }
+        finally {
+            try {
+                out.close();
+
+                printFile(out.toByteArray());
+
+            } catch (Exception ex) {
+                  LoggerFactory.getLogger(RolesXML.class).error(ex.getMessage(), ex);
+            }
+        }
+
+
+    }
+    /**
+     * Print one byte array in File
+     * Encrypt that file with the key
+     * @param bytes
+     */
+    public void printFile(byte[] bytes) throws Exception {
+        InputStream in;
+
+
+        in = new ByteArrayInputStream(bytes);
+
+        FileOutputStream out = new FileOutputStream("roles.xml");
+
+
+        byte[] input = new byte[1024];
+        int bytesRead;
+        while ((bytesRead = in.read(input)) != -1) {
+            out.write(input, 0, bytesRead);
+            out.flush();
+        }
+
+        out.close();
+        in.close();
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/User.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/User.java
new file mode 100755
index 0000000..e25bbcc
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/User.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.users;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Class that saves information about one user
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ * @author Luís Bastião Silva <bastiao at bmd-software.com>
+ */
+public class User implements UserRoleManager{
+
+    private final String username;
+    private String hash;        //stores the Hash of this user (username + admin + passwordHash)
+    private final boolean admin;
+
+    private List<Role> roles = new ArrayList<>();
+
+    public User(String username, String Hash, boolean admin){
+        this.username = username;
+        this.admin = admin;
+        this.hash = Hash;
+    }
+
+    public String getUsername(){
+        return username;
+    }
+
+    public boolean isAdmin(){
+        return admin;
+    }
+
+    public boolean verifyPassword(String passwordHash){
+        String tempHash = HashService.getSHA1Hash(username + admin + passwordHash);
+
+        return this.hash.equals(tempHash);
+    }
+
+    public void addRole(Role r)
+    {
+        this.roles.add(r);
+    }
+
+    public boolean hasRole(Role r)
+    {
+        return this.roles.contains(r);
+    }
+
+    public boolean changePassword(String oldPassHash, String newPassHash){
+        String tempHash = HashService.getSHA1Hash(username + admin + oldPassHash);
+
+        if(!hash.equals(tempHash))
+            return false;
+
+
+        tempHash = HashService.getSHA1Hash(username + admin + newPassHash);
+
+        hash = tempHash;
+        return true;
+    }
+
+    protected String getPasswordHash(){
+        return hash;
+    }
+
+    public boolean resetPassword(String newPassHash){
+        if(newPassHash == null || newPassHash.equals(""))
+            return false;
+
+        String tempHash = HashService.getSHA1Hash(username + admin + newPassHash);
+
+        hash = tempHash;
+
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == null || other.getClass() != getClass()) {
+            return false;
+        }
+
+        if (other == this) {
+            return true;
+        }
+
+        User tmp = (User) other;
+
+        if (username.equals(tmp.username) && hash.equals(tmp.hash)
+                && admin == tmp.admin) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 67 * hash + Objects.hashCode(this.username);
+        hash = 67 * hash + Objects.hashCode(this.hash);
+        hash = 67 * hash + (this.admin ? 1 : 0);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" + username + (admin ? ", admin" : "") + '}';
+    }
+
+    public List<Role> getRoles() {
+        return roles;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserFileHandle.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserFileHandle.java
new file mode 100755
index 0000000..105b470
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserFileHandle.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ * This class provides encryptation to the file that saves users information
+ * Uses the AES algorithim with 128 bit key
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class UserFileHandle {
+
+    private String filename;
+    private String keyFile;
+
+    private Cipher cipher;
+    private Key key;
+    private boolean encrypt;
+
+    public UserFileHandle() throws IOException {
+        filename = Platform.homePath() + "users.xml";
+        encrypt = ServerSettings.getInstance().isEncryptUsersFile();
+        try {
+
+            if(encrypt){
+                keyFile = "users.key";
+
+                try {
+                    ObjectInputStream in = new ObjectInputStream(new FileInputStream(keyFile));
+                    key = (Key) in.readObject();
+                    in.close();
+
+                } catch (FileNotFoundException ex) {
+                    KeyGenerator gen = KeyGenerator.getInstance("AES");
+
+                    gen.init(128, new SecureRandom());
+                    key = gen.generateKey();
+
+                    try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(keyFile))) {
+                        out.writeObject(key);
+                    }
+                }
+
+                cipher = Cipher.getInstance("AES");
+            }
+
+        } catch (NoSuchAlgorithmException | ClassNotFoundException | NoSuchPaddingException ex) {
+            LoggerFactory.getLogger(UserFileHandle.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    /**
+     * Print one byte array in File
+     * Encrypt that file with the key
+     * @param bytes
+     */
+    public void printFile(byte[] bytes) throws Exception {
+        InputStream in;
+
+        if(encrypt){
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+
+            byte[] encryptedBytes = cipher.doFinal(bytes);
+            in = new ByteArrayInputStream(encryptedBytes);
+        }
+        else
+            in = new ByteArrayInputStream(bytes);
+
+        FileOutputStream out = new FileOutputStream(filename);
+        
+
+        byte[] input = new byte[1024];
+        int bytesRead;
+        while ((bytesRead = in.read(input)) != -1) {
+            out.write(input, 0, bytesRead);
+            out.flush();
+        }
+
+        out.close();
+        in.close();
+    }
+
+    /** Retrieve the contents of the users configuration file.
+     * @return a byte array, or null if the configuration file is not available or corrupted
+     * @throws IOException on a failed attempt to read the file
+     */
+    public byte[] getFileContent() throws IOException {
+        try {
+            try (FileInputStream fin = new FileInputStream(filename);
+                    ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+                byte[] data = new byte[1024];
+                int bytesRead;
+
+                while ((bytesRead = fin.read(data)) != -1) {
+                    out.write(data, 0, bytesRead);
+                    out.flush();
+                }
+
+                if(encrypt){
+                    cipher.init(Cipher.DECRYPT_MODE, key);
+                    byte[] Bytes = cipher.doFinal(out.toByteArray());
+                    return Bytes;
+                }
+                
+                return out.toByteArray();
+            }
+        } catch (FileNotFoundException ex) {
+            LoggerFactory.getLogger(UserFileHandle.class).info("No such users file \"{}\", will create one with default settings.", filename);
+        } catch (IllegalBlockSizeException ex) {
+            LoggerFactory.getLogger(UserFileHandle.class).error("Users file \"{}\" is corrupted, will override it with default settings.", filename, ex);
+        } catch (InvalidKeyException ex) {
+            LoggerFactory.getLogger(UserFileHandle.class).error("Invalid Key to decrypt users file! Please contact your system administator.");
+            System.exit(1); // FIXME this is too dangerous
+        }
+        catch(BadPaddingException ex){
+            LoggerFactory.getLogger(UserFileHandle.class).error("Invalid Key to decrypt users file! Please contact your system administator.");
+            System.exit(2); // FIXME this is too dangerous
+        }
+        return null;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserON.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserON.java
new file mode 100755
index 0000000..91b62b6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserON.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+
+
+/**
+ * This class stores the information about one active user
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class UserON implements Serializable {
+    private int userID;
+    private String username;
+    private String host;
+
+    private Date loginTime;
+
+    //private User userfer;
+
+    public UserON(int userID, String username, String host){
+        this.userID = userID;
+        this.username = username;
+        this.host = host;
+
+        loginTime = new Date();
+    }
+
+    /**
+     * @return the username
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * @return the userID
+     */
+    public int getUserID() {
+        return userID;
+    }
+
+    /**
+     * @return the host
+     */
+    public String getHost() {
+        return host;
+    }
+
+    public Date getLoginTime(){
+        return loginTime;
+    }
+
+
+    @Override
+    public boolean equals(Object other) {
+        if (other == null || other.getClass() != getClass()) {
+            return false;
+        }
+
+        if (other == this) {
+            return true;
+        }
+
+        UserON tmp = (UserON) other;
+
+        if (userID == tmp.userID && username.equals(tmp.username) && host.equals(tmp.host)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString(){
+        Calendar cal = Calendar.getInstance();
+        Calendar cal2 = Calendar.getInstance();
+        cal.setTime(loginTime);
+        cal2.setTime(new Date());
+
+        long milliseconds1 = cal.getTimeInMillis();
+        long milliseconds2 = cal2.getTimeInMillis();
+
+        long diff = milliseconds2 - milliseconds1;
+
+        long diffHours = diff / (60 * 60 * 1000);
+        diff = diff % (60 * 60 * 1000);
+        long diffMinutes = diff / (60 * 1000);
+        diff = diff % (60 * 1000);
+        long diffSeconds = diff / 1000;
+
+        return host + " - " + username + ", Login Time: " + diffHours + ":" + diffMinutes + ":" + diffSeconds ;
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserRoleManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserRoleManager.java
new file mode 100644
index 0000000..0f2956f
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserRoleManager.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public interface UserRoleManager {
+
+    public boolean hasRole(Role r);
+    public void addRole(Role r);
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessions.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessions.java
new file mode 100755
index 0000000..117d7ff
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessions.java
@@ -0,0 +1,232 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.rGUI.interfaces.controllers.IActiveSessions;
+import pt.ua.dicoogle.rGUI.server.UserFeatures;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class UserSessions implements IActiveSessions {
+
+    //Active users lists
+    private HashMap<Integer, UserON> usersTable;
+    private HashMap<Integer, UserFeatures> usersFeatures;
+    // Saves the current administrator's user
+    private int adminID;
+    // Actual ID in Table
+    private int ID;
+    private static UserSessions instance = null;
+
+    public static synchronized UserSessions getInstance() {
+        if (instance == null) {
+            instance = new UserSessions();
+        }
+
+        return instance;
+    }
+
+    private UserSessions() {
+        usersTable = new HashMap<Integer, UserON>();
+        usersFeatures = new HashMap<Integer, UserFeatures>();
+
+        ID = 0;
+        adminID = - 1;
+    }
+
+    /**
+     *
+     * @param username
+     * @param host
+     * @return user session ID
+     */
+    public int userLogin(User user, String host, UserFeatures userF) {
+        if (userF == null) {
+            throw new NullPointerException("UserFeatures can't be null!");
+        }
+
+        int id = login(user, host, false);
+
+        usersFeatures.put(id, userF);
+        return id;
+    }
+
+    /**
+     *
+     * @param username
+     * @param host
+     * @return false if the administrator is already connected
+     */
+    public synchronized int adminLogin(User adminUser, String host) {
+        if (adminID == -1 && adminUser.isAdmin()) {
+            adminID = login(adminUser, host, true);
+
+            return adminID;
+        }
+
+        return -1;
+    }
+
+    private int login(User user, String host, boolean admin) {
+        int returnValue = ID;
+
+        usersTable.put(ID, new UserON(ID, user.getUsername(), host));
+
+        //write the log
+        LoggerFactory.getLogger(UserSessions.class).info("{} - {} : {} logged in",
+                new Object[]{host, user.getUsername(), admin ? "administrator" : "user"});
+//        UserSessionsLog.getInstance().login(user.getUsername(), host, admin);
+
+        //increase and mantain ID as a positive integer
+        ID = (ID + 1) & Integer.MAX_VALUE;
+
+        return returnValue;
+    }
+
+    /**
+     * Set the UserFeatures related to admin
+     * @param userF
+     * @return
+     */
+    public boolean setAdminUserFeatures(UserFeatures userF) {
+        if (!usersFeatures.containsKey(adminID)) {
+            usersFeatures.put(adminID, userF);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Remove one user from active users list
+     *
+     * @param userID
+     * @return  true if the user exists and has been removed from the list
+     */
+    public boolean userLogout(UserFeatures userF) {
+        int id;
+        Iterator<Integer> en = usersFeatures.keySet().iterator();
+
+        while (en.hasNext()) {
+            id = en.next();
+
+            //this is a workarround, must be more efficient
+            if (usersFeatures.get(id) == userF) {
+                //usersFeatures.remove(id);
+                en.remove();
+                UserON user = usersTable.remove(id);
+
+                if (user != null) {
+                    LoggerFactory.getLogger(UserSessions.class).info("{} - {} : user logged out",
+                            user.getHost(), user.getUsername());
+//                    UserSessionsLog.getInstance().logout(user.getUsername(), user.getHost(), false);
+                }
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public synchronized void adminLogout() {
+        if (adminID != -1) {
+            UserON user = usersTable.get(adminID);
+
+            if (user != null) {
+                    LoggerFactory.getLogger(UserSessions.class).info("{} - {} : administrator logged out",
+                            user.getHost(), user.getUsername());
+//                UserSessionsLog.getInstance().logout(user.getUsername(), user.getHost(), true);
+            }
+        }
+        adminID = -1;
+    }
+
+    /**
+     *
+     * @return the current usersTable
+     * @throws RemoteException
+     */
+    @Override
+    public HashMap<Integer, UserON> getUsersTable() throws RemoteException {
+        return usersTable;
+    }
+
+    /**
+     * Logout one user 
+     *
+     * @param userID
+     * @return
+     * @throws RemoteException
+     */
+    @Override
+    public boolean adminLogoutUser(int userID) throws RemoteException {
+        boolean value = false;
+
+        UserFeatures userF;
+
+        if ((userF = usersFeatures.get(userID)) != null) {
+            try {
+                userF.logout();
+                value = true;
+
+            } catch (RemoteException ex) {
+                LoggerFactory.getLogger(UserSessions.class).error(ex.getMessage(), ex);
+            }
+        }
+
+        return value;
+    }
+
+    @Override
+    public int getAdminID() throws RemoteException {
+        return adminID;
+    }
+
+    /*
+     * Logout All Users
+     */
+    public void adminLogoutAllUsers() throws RemoteException {
+        Iterator<Integer> en = usersFeatures.keySet().iterator();
+        UserFeatures userF;
+
+        while (en.hasNext()) {
+            userF = usersFeatures.get(en.next());
+            if (userF != null) {
+                try {
+                    userF.logout();
+                } catch (RemoteException ex) {
+                    LoggerFactory.getLogger(UserSessions.class).error(ex.getMessage(), ex);
+                }
+            }
+        }
+    }
+
+    public void loginFailed(String username, String host, boolean admin) {
+        LoggerFactory.getLogger(UserSessions.class).info("{} - {} : {} login failed",
+                new Object[]{username, host, admin ? "administrator" : "user"});
+        //UserSessionsLog.getInstance().loginFailed(username, host, admin);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessionsLog.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessionsLog.java
new file mode 100755
index 0000000..fbc7978
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UserSessionsLog.java
@@ -0,0 +1,173 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+ at Deprecated
+public class UserSessionsLog {
+
+    private String sessionsLogFile;
+    private static UserSessionsLog instance = null;
+
+    public static synchronized UserSessionsLog getInstance() {
+        if (instance == null) {
+            instance = new UserSessionsLog();
+        }
+        return instance;
+    }
+
+    private UserSessionsLog() {
+        sessionsLogFile = Platform.homePath() + "sessions.log";
+    }
+
+    public void login(String username, String host, boolean admin) {
+        String line;
+
+        if (admin)
+            line = host + " - " + username + ": administrator logged";
+        else
+            line = host + " - " + username + ": user logged";
+  
+        writeLine(line, true);
+    }
+
+    public void loginFailed(String username, String host, boolean admin) {
+        String line;
+
+        if (admin) {
+            line = host + " - " + username + ": administrator login failed";
+        } else {
+            line = host + " - " + username + ": user login failed";
+        }
+
+        writeLine(line, true);
+    }
+
+    public void logout(String username, String host, boolean admin) {
+        String line;
+
+        if (admin) {
+            line = host + " - " + username + ": administrator logged out";
+            writeLine(line, false);
+        } else {
+            line = host + " - " + username + ": user logged out";
+            writeLine(line, true);
+        }
+    }
+
+    /**
+     *
+     * @param line
+     * @param send - indicates whether or not to send to the controller
+     */
+    private void writeLine(String line, boolean send) {
+        BufferedWriter out = null;
+
+        //DebugManager.getInstance().debug(line);
+
+//        Date now = new Date();
+//        String tmp = now.toString() + ": " + line + "\n";
+
+        if(send) {
+            LoggerFactory.getLogger(UserSessions.class).info(line);
+//            Logs.getInstance().addSessionsLog(tmp);
+        }
+        
+//        try {
+//            semFile.acquire();
+//            out = new BufferedWriter(new FileWriter(sessionsLogFile, true));
+//            out.write(tmp);
+//            out.close();
+//        } catch (InterruptedException ex) {
+//            Logger.getLogger(UserSessionsLog.class.getName()).log(Level.SEVERE, null, ex);
+//        } catch (IOException ex) {
+//            Logger.getLogger(UserSessionsLog.class.getName()).log(Level.SEVERE, null, ex);
+//        } finally {
+//            try {
+//                out.close();
+//            } catch (IOException ex) {
+//                Logger.getLogger(UserSessionsLog.class.getName()).log(Level.SEVERE, null, ex);
+//            }
+//        }
+//
+//        semFile.release();
+    }
+
+    public synchronized void cleanLog() {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(sessionsLogFile));
+            out.write("");
+            out.close();
+
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(UserSessions.class).error("Failed to clean log", ex);
+        } finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(UserSessions.class).error("Failed to clean log", ex);
+            }
+        }
+    }
+
+    public synchronized String readLog() {
+        String ret = "";
+
+        BufferedReader in = null;
+        try {
+            String tmp;
+
+
+            in = new BufferedReader(new FileReader(sessionsLogFile));
+
+            while ((tmp = in.readLine()) != null) {
+                ret = ret + "\n" + tmp;
+            }
+
+            in.close();
+
+        } catch (IOException ex) {
+            LoggerFactory.getLogger(UserSessions.class).error("Failed to read log", ex);
+        } finally {
+            try {
+                in.close();
+
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(UserSessions.class).error("Failed to read log", ex);
+            }
+        }
+        
+        ret = ret + "\n";
+
+        return ret;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersStruct.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersStruct.java
new file mode 100755
index 0000000..e68d498
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersStruct.java
@@ -0,0 +1,138 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+import java.util.Set;
+
+/**
+ * This class stores the list of users of Dicoogle
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class UsersStruct {
+    private HashMap<String, User> users;
+
+    private static UsersStruct instance = null ;
+
+    // count the number of administrators
+    private int numberOfAdmins;
+
+    public static synchronized UsersStruct getInstance() {
+        if (instance == null) {
+            instance = new UsersStruct();
+        }
+
+        return instance;
+    }
+
+
+
+    private UsersStruct(){
+       reset();
+    }
+
+    
+    /**
+     * Insert one default user
+     * Username: "dicoogle"
+     * Password: "DCpassword" (hashed)
+     *
+     * This user is administrator
+     */
+    public void setDefaults(){
+        //DebugManager.getInstance().debug("Setting default user settings");
+
+        String username = "dicoogle";
+        boolean admin = true;
+        String passPlainText = "dicoogle";
+
+        String passHash = HashService.getSHA1Hash(passPlainText);             //password Hash
+        String Hash = HashService.getSHA1Hash(username + admin + passHash);   //user Hash
+
+        users = new HashMap<String, User>();
+        users.put("dicoogle", new User(username, Hash, admin));
+    }
+
+    /**
+     * Used only by UsersXML to reset User Settings
+     */
+    protected void reset(){
+        users = new HashMap<String, User>();
+        numberOfAdmins = 0;
+    }
+
+    
+    /**
+     * Insert user in the List of users
+     *
+     * @param user
+     * @return  true - if succeeded. false - if the username already exists
+     */
+    public boolean addUser(User user){
+        if(users.containsKey(user.getUsername()))
+            return false;
+
+        users.put(user.getUsername(), user);
+
+        if(user.isAdmin())
+            numberOfAdmins++;
+        
+        return true;
+    }
+
+    /**
+     *  Removes one user from de list
+     *  Maintains at least one administrator in the list
+     *      (refuses to remove the last one)
+     * 
+     * @param username
+     * @return
+     */
+    public boolean removeUser(String username){
+        if(username == null)
+            return false;
+        
+        User user = users.get(username);
+        if (user == null)
+            return false;
+
+        if(user.isAdmin() && numberOfAdmins == 1)
+            return false;
+        else if(user.isAdmin())
+            numberOfAdmins--;
+
+        users.remove(username);
+        return true;
+    }
+
+    public Collection<User> getUsers(){
+        return users.values();
+    }
+
+    public Set<String> getUsernames(){
+        return users.keySet();
+    }
+
+    public User getUser(String username){
+        return users.get(username);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersXML.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersXML.java
new file mode 100755
index 0000000..7a1d5db
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/users/UsersXML.java
@@ -0,0 +1,259 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.users;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * This class saves the list of users to XML
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class UsersXML extends DefaultHandler
+{
+    private UsersStruct users = UsersStruct.getInstance();
+    private boolean isUsers = false ;
+
+    private String username;
+    private String Hash;
+    private boolean admin;
+    private String roles;
+
+
+    public UsersXML()
+    {
+        username = "";
+        Hash = "";
+        roles = "";
+        admin = false;
+    }
+
+
+    @Override
+    public void startElement( String uri, String localName, String qName,
+            Attributes attribs )
+    {
+
+
+
+        if (localName.equals("Users"))
+        {
+            isUsers = true ;
+        }
+        else if (this.isUsers && localName.equals("user"))
+        {
+            this.username = this.resolveAttrib("username", attribs, "xp");
+            this.Hash = this.resolveAttrib("hash", attribs, "xp");
+
+            String temp = this.resolveAttrib("admin", attribs, "xp");
+            if(temp.equals("true"))
+                this.admin = true;
+            else
+                this.admin = false;
+            this.roles = this.resolveAttrib("roles", attribs, "xp");
+
+        }
+        
+    }
+
+
+    @Override
+    public void endElement( String uri, String localName, String qName )
+    {
+
+        if (localName.equals("Users"))
+        {
+            isUsers = false ;
+        }
+        else if( localName.equals( "user" ) )
+        {
+
+            User u = new User(username, Hash, admin);
+            users.addUser(u);
+            if (roles!=null)
+            {
+                String [] rolesTmp = roles.split(",");
+                for (int i = 0; i<rolesTmp.length; i++)
+                {
+                    Role role = RolesStruct.getInstance().getRole(rolesTmp[i]);
+                    u.addRole(role);
+                }
+
+            }
+        }
+        
+    }
+
+     private String resolveAttrib( String attr, Attributes attribs, String defaultValue) {
+         String tmp = attribs.getValue(attr);
+         return (tmp!=null)?(tmp):(defaultValue);
+     }
+
+
+    public UsersStruct getXML()
+    {
+        users.reset();
+        
+        try
+        {
+            UserFileHandle file = new UserFileHandle();
+            byte[] xml = file.getFileContent();
+            
+            if (xml == null)
+            {
+                //DebugManager.getInstance().debug("Setting users default, writing a file with the default information!");
+                users.setDefaults();
+                printXML();
+                return users;
+            }
+
+
+            // Never throws the exception cause file not exists so need try catch
+            InputSource src = new InputSource( new ByteArrayInputStream(xml) );
+            XMLReader r = XMLReaderFactory.createXMLReader();
+            r.setContentHandler(this);
+            r.parse(src);
+            return users;
+        }
+        catch (SAXException | IOException ex)
+        {
+            LoggerFactory.getLogger(UsersXML.class).error(ex.getMessage(), ex);
+        }
+        return null;
+    }
+
+    /**
+     * Print the users information to the XML file
+     */
+    public void printXML()
+    {
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+       
+
+        PrintWriter pw = new PrintWriter(out);
+        StreamResult streamResult = new StreamResult(pw);
+        SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
+        //      SAX2.0 ContentHandler.
+        TransformerHandler hd = null;
+        try
+        {
+            hd = tf.newTransformerHandler();
+        } catch (TransformerConfigurationException ex)
+        {
+            LoggerFactory.getLogger(UsersXML.class).error(ex.getMessage(), ex);
+        }
+        
+        Transformer serializer = hd.getTransformer();
+        serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        serializer.setOutputProperty(OutputKeys.METHOD, "xml");
+        serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+        serializer.setOutputProperty(OutputKeys.STANDALONE, "yes");   
+        try
+        {
+            hd.setResult(streamResult);
+            hd.startDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(UsersXML.class).error(ex.getMessage(), ex);
+        }
+
+        AttributesImpl atts = new AttributesImpl();
+        try
+        {
+            //root element
+            hd.startElement("", "", "Users", atts);
+
+            Iterator<User> us = UsersStruct.getInstance().getUsers().iterator();
+
+            atts.clear();
+            while (us.hasNext())
+            {
+                User user = us.next();
+                
+                atts.addAttribute("", "", "username", "", user.getUsername());
+                atts.addAttribute("", "", "hash", "", user.getPasswordHash()) ;
+
+                String temp = "false";
+                if(user.isAdmin())
+                    temp = "true";
+                if (user.getRoles()!=null&&user.getRoles().size()>0)
+                {
+                    String roles = "";
+                    for (Role r : user.getRoles())
+                    {
+                        roles+=r.getName()+",";
+                    }
+                    StringUtils.removeEnd(roles, ",");
+
+
+                    atts.addAttribute("", "", "roles", "", roles ) ;
+                }
+
+                atts.addAttribute("", "", "admin", "", temp) ;
+
+                hd.startElement("", "", "user", atts);
+                atts.clear();
+                hd.endElement("", "", "user");
+            }
+            hd.endElement("", "", "Users");
+
+
+            hd.endDocument();
+        } catch (SAXException ex)
+        {
+            LoggerFactory.getLogger(UsersXML.class).error(ex.getMessage(), ex);
+        }
+        finally {
+            try {
+                out.close();
+                
+                UserFileHandle file = new UserFileHandle();
+                file.printFile(out.toByteArray());
+            } catch (Exception ex) {
+                  LoggerFactory.getLogger(UsersXML.class).error(ex.getMessage(), ex);
+            }
+        }
+
+
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/AbstractCacheFilter.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/AbstractCacheFilter.java
new file mode 100644
index 0000000..922fb64
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/AbstractCacheFilter.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ */
+
+package pt.ua.dicoogle.server.web;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/** A filter that can deal with non-static content caching.
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public abstract class AbstractCacheFilter implements Filter {
+    
+    public static String CACHE_CONTROL_HEADER = "Cache-Control";
+    public static String IF_NONE_MATCH_HEADER = "If-None-Match";
+    public static String ETAG_HEADER = "ETag";
+
+    public static String CACHE_CONTROL_PARAM = "cacheControl";
+
+    private String cacheControl;
+
+    @Override
+    public void init(FilterConfig fc) throws ServletException {
+        this.cacheControl = fc.getInitParameter(CACHE_CONTROL_PARAM);
+    }
+
+    @Override
+    public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain fc) throws IOException, ServletException {
+        if (sresp instanceof HttpServletResponse && sreq instanceof HttpServletRequest) {
+            HttpServletResponse resp = (HttpServletResponse) sresp;
+            HttpServletRequest req = (HttpServletRequest)sreq;
+
+            if (cacheControl != null) {
+                resp.addHeader(CACHE_CONTROL_HEADER, cacheControl);
+            }
+            String ifNoneMatchParam = req.getHeader(IF_NONE_MATCH_HEADER);
+            String thisETag = this.etag(req);
+            if (thisETag != null) {
+                resp.setHeader(ETAG_HEADER, thisETag);
+                if (ifNoneMatchParam != null) {
+                    List<String> matches = Arrays.asList(ifNoneMatchParam.split(" *, *"));
+                    if (matches.contains(thisETag)) {
+                        // intercept request, send 304
+                        resp.setStatus(304);
+                        return;
+                    }
+                }
+            }
+        }
+        fc.doFilter(sreq, sresp);
+    }
+
+    protected abstract String etag(HttpServletRequest req);
+
+    @Override
+    public void destroy() {
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/CORSFilter.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/CORSFilter.java
new file mode 100644
index 0000000..ae549ae
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/CORSFilter.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ */
+
+package pt.ua.dicoogle.server.web;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/** Since CrossOriginFilter doesn't work, this is a custom implementation of the same thing.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class CORSFilter implements Filter {
+    
+    public static String ACCESS_CONTROL_ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin";
+    public static String ACCESS_CONTROL_ALLOW_HEADERS_HEADER = "Access-Control-Allow-Headers";
+    public static String ACCESS_CONTROL_ALLOW_METHODS_HEADER = "Access-Control-Allow-Methods";
+    public static String ACCESS_CONTROL_ALLOW_AUTHORIZATION_HEADER = "Authorization";
+
+    public static String ALLOWED_ORIGINS_PARAM = "allowedOrigins";
+    public static String ALLOWED_HEADERS_PARAM = "allowedHeaders";
+    public static String ALLOWED_METHODS_PARAM = "allowedMethods";
+    public static String ALLOWED_AUTHORIZATION_PARAM = "allowedAuthorization";
+
+    private String allowedOrigins;
+    private String allowedHeaders;
+    private String allowedMethods;
+    private String allowedAuthorization;
+
+    @Override
+    public void init(FilterConfig fc) throws ServletException {
+        allowedOrigins = fc.getInitParameter(ALLOWED_ORIGINS_PARAM);
+        allowedHeaders = fc.getInitParameter(ALLOWED_HEADERS_PARAM);
+        allowedMethods = fc.getInitParameter(ALLOWED_METHODS_PARAM);
+        allowedMethods = fc.getInitParameter(ALLOWED_METHODS_PARAM);
+        allowedAuthorization = fc.getInitParameter(ALLOWED_AUTHORIZATION_PARAM);
+        if (allowedMethods == null) {
+            allowedMethods = "GET,POST,HEAD";
+        }
+        if (allowedHeaders == null) {
+            allowedHeaders = "X-Requested-With,Content-Type,Accept,Origin,Authorization,Content-Length";
+        }
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain fc) throws IOException, ServletException {
+        if (sresp instanceof HttpServletResponse) {
+            HttpServletResponse resp = (HttpServletResponse) sresp;
+            if (allowedOrigins != null) {
+                resp.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, allowedOrigins);
+            }
+            if (allowedHeaders!= null) {
+                resp.addHeader(ACCESS_CONTROL_ALLOW_HEADERS_HEADER, allowedHeaders);
+            }
+            if (allowedAuthorization!=null)
+                resp.addHeader(ACCESS_CONTROL_ALLOW_AUTHORIZATION_HEADER, allowedAuthorization);
+            resp.addHeader(ACCESS_CONTROL_ALLOW_METHODS_HEADER, allowedMethods);
+        }
+        if (sreq instanceof HttpServletRequest) {
+            HttpServletRequest req = (HttpServletRequest)sreq;
+            if (req.getMethod().equalsIgnoreCase("OPTIONS")) {
+                return;
+            }
+        }
+        fc.doFilter(sreq, sresp);
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/DicoogleWeb.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/DicoogleWeb.java
new file mode 100755
index 0000000..ce72e64
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/DicoogleWeb.java
@@ -0,0 +1,357 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web;
+
+import org.apache.commons.codec.digest.Md5Crypt;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.plugins.webui.WebUIPlugin;
+import pt.ua.dicoogle.server.web.rest.VersionResource;
+import pt.ua.dicoogle.server.web.servlets.RestletHttpServlet;
+import pt.ua.dicoogle.server.web.servlets.ExportToCSVServlet;
+import pt.ua.dicoogle.server.web.servlets.SettingsServlet;
+import pt.ua.dicoogle.server.web.servlets.TagsServlet;
+import pt.ua.dicoogle.server.web.servlets.ExportCSVToFILEServlet;
+import pt.ua.dicoogle.server.web.servlets.SearchHolderServlet;
+import pt.ua.dicoogle.server.web.servlets.IndexerServlet;
+import pt.ua.dicoogle.server.web.servlets.ImageServlet;
+import pt.ua.dicoogle.server.web.servlets.search.ExportServlet;
+import pt.ua.dicoogle.server.web.servlets.search.ExportServlet.ExportType;
+import pt.ua.dicoogle.server.web.servlets.search.ProvidersServlet;
+import pt.ua.dicoogle.server.web.servlets.search.SearchServlet;
+import pt.ua.dicoogle.server.web.servlets.search.SearchServlet.SearchType;
+import pt.ua.dicoogle.server.web.servlets.search.WadoServlet;
+import pt.ua.dicoogle.server.web.servlets.accounts.LoginServlet;
+import pt.ua.dicoogle.server.web.servlets.accounts.UserServlet;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.server.web.servlets.management.AETitleServlet;
+import pt.ua.dicoogle.server.web.servlets.management.DicomQuerySettingsServlet;
+import pt.ua.dicoogle.server.web.servlets.management.ForceIndexing;
+import pt.ua.dicoogle.server.web.servlets.management.IndexerSettingsServlet;
+import pt.ua.dicoogle.server.web.servlets.management.LoggerServlet;
+import pt.ua.dicoogle.server.web.servlets.management.RemoveServlet;
+import pt.ua.dicoogle.server.web.servlets.management.RunningTasksServlet;
+import pt.ua.dicoogle.server.web.servlets.management.ServerStorageServlet;
+import pt.ua.dicoogle.server.web.servlets.management.ServicesServlet;
+import pt.ua.dicoogle.server.web.servlets.management.TransferOptionsServlet;
+
+import java.io.File;
+import java.net.URL;
+import java.util.EnumSet;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.eclipse.jetty.webapp.WebAppContext;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.handler.HandlerList;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlets.GzipFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.server.LegacyRestletApplication;
+import pt.ua.dicoogle.server.web.servlets.accounts.LogoutServlet;
+import pt.ua.dicoogle.server.web.servlets.management.UnindexServlet;
+import pt.ua.dicoogle.server.web.servlets.search.DumpServlet;
+import pt.ua.dicoogle.server.web.servlets.webui.WebUIModuleServlet;
+import pt.ua.dicoogle.server.web.servlets.webui.WebUIServlet;
+import pt.ua.dicoogle.server.web.utils.LocalImageCache;
+import pt.ua.dicoogle.server.PluginRestletApplication;
+import pt.ua.dicoogle.server.web.utils.SimpleImageRetriever;
+
+/**
+ * @author António Novo <antonio.novo at ua.pt>
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Frederico Valente
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class DicoogleWeb {
+
+    private static final Logger logger = LoggerFactory.getLogger(DicoogleWeb.class);
+    /**
+     * Sets the path where the web-pages/scripts or .war are.
+     */
+    public static final String WEBAPPDIR = "webapp";
+
+    /**
+     * Sets the context path used to serve the contents.
+     */
+    public static final String CONTEXTPATH = "/";
+    private LocalImageCache cache = null;
+    private Server server = null;
+    private final int port;
+
+    private final ContextHandlerCollection contextHandlers;
+    private ServletContextHandler pluginHandler = null;
+    private PluginRestletApplication pluginApp = null;
+    private ServletContextHandler legacyHandler = null;
+    private LegacyRestletApplication legacyApp = null;
+
+    /**
+     * Initializes and starts the Dicoogle Web service.
+     * @param port the server port
+     * @throws java.lang.Exception
+     */
+    public DicoogleWeb(int port) throws Exception {
+        logger.info("Starting Web Services in DicoogleWeb. Port: {}", port);
+        System.setProperty("org.apache.jasper.compiler.disablejsr199", "true");
+        //System.setProperty("org.mortbay.jetty.webapp.parentLoaderPriority", "true");
+        //System.setProperty("production.mode", "true");
+
+        this.port = port;
+
+        // "build" the input location, based on the www directory/.war chosen
+        final URL warUrl = Thread.currentThread().getContextClassLoader().getResource(WEBAPPDIR);
+        final String warUrlString = warUrl.toExternalForm();
+
+        //setup the DICOM to PNG image servlet, with a local cache
+        cache = new LocalImageCache("dic2png", 300, 900, new SimpleImageRetriever()); // pooling rate of 12/hr and max un-used cache age of 15 minutes
+        final ServletContextHandler dic2png = createServletHandler(new ImageServlet(cache), "/dic2png");
+        cache.start(); // start the caching system
+
+        // setup the DICOM to PNG image servlet
+        final ServletContextHandler dictags = createServletHandler(new TagsServlet(), "/dictags");
+
+        // setup the Export to CSV Servlet
+        final ServletContextHandler csvServletHolder = createServletHandler(new ExportToCSVServlet(), "/export");
+        File tempDir = new File(ServerSettings.getInstance().getPath());
+        csvServletHolder.addServlet(new ServletHolder(new ExportCSVToFILEServlet(tempDir)), "/exportFile");
+
+        // setup the search (DIMSE-service-user C-FIND ?!?) servlet
+        //final ServletContextHandler search = new ServletContextHandler(ServletContextHandler.SESSIONS); // servlet with session support enabled
+        //search.setContextPath(CONTEXTPATH);
+        //search.addServlet(new ServletHolder(new SearchServlet()), "/search");
+
+        /*hooks = getRegisteredHookActions();
+         plugin.addServlet(new ServletHolder(new PluginsServlet(hooks)), "/plugin/*");
+         */
+
+        // setup the web pages/scripts app
+        final WebAppContext webpages = new WebAppContext(warUrlString, CONTEXTPATH);
+        webpages.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false"); // disables directory listing
+        webpages.setInitParameter("useFileMappedBuffer", "false");
+        webpages.setInitParameter("cacheControl", "public, max-age=2592000"); // cache for 30 days
+        webpages.setInitParameter("etags", "true"); // generate and handle weak entity validation tags
+        webpages.setDisplayName("webapp");
+        webpages.setWelcomeFiles(new String[]{"index.html"});
+        webpages.addServlet(new ServletHolder(new SearchHolderServlet()), "/search/holders");
+        webpages.addFilter(GzipFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
+        
+        this.pluginApp = new PluginRestletApplication();
+        this.pluginHandler = createServletHandler(new RestletHttpServlet(this.pluginApp), "/ext/*");
+
+        this.legacyApp = new LegacyRestletApplication();
+        this.legacyHandler = createServletHandler(new RestletHttpServlet(this.legacyApp), "/legacy/*");
+        
+        // Add Static RESTlet Plugins
+        PluginRestletApplication.attachRestPlugin(new VersionResource());
+        
+        // list the all the handlers mounted above
+        Handler[] handlers = new Handler[]{
+            pluginHandler,
+            legacyHandler,
+            dic2png,
+            dictags,
+            createServletHandler(new IndexerServlet(), "/indexer"), // DEPRECATED
+            createServletHandler(new SettingsServlet(), "/settings"),
+            csvServletHolder,
+            createServletHandler(new LoginServlet(), "/login"),
+            createServletHandler(new LogoutServlet(), "/logout"),
+            createServletHandler(new UserServlet(), "/user"),
+            createServletHandler(new SearchServlet(), "/search"),
+            createServletHandler(new SearchServlet(SearchType.PATIENT), "/searchDIM"),
+            createServletHandler(new DumpServlet(), "/dump"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.path) , "/management/settings/index/path"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.zip), "/management/settings/index/zip"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.effort), "/management/settings/index/effort"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.thumbnail), "/management/settings/index/thumbnail"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.watcher), "/management/settings/index/watcher"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.thumbnailSize), "/management/settings/index/thumbnail/size"),
+            createServletHandler(new IndexerSettingsServlet(IndexerSettingsServlet.SettingsType.all), "/management/settings/index"),
+            createServletHandler(new TransferOptionsServlet(), "/management/settings/transfer"),
+            createServletHandler(new WadoServlet(), "/wado"),
+            createServletHandler(new ProvidersServlet(), "/providers"),
+            createServletHandler(new DicomQuerySettingsServlet(), "/management/settings/dicom/query"),
+            createServletHandler(new ForceIndexing(), "/management/tasks/index"),
+            createServletHandler(new UnindexServlet(), "/management/tasks/unindex"),
+            createServletHandler(new RemoveServlet(), "/management/tasks/remove"),
+            createServletHandler(new ServicesServlet(ServicesServlet.STORAGE), "/management/dicom/storage"),
+            createServletHandler(new ServicesServlet(ServicesServlet.QUERY), "/management/dicom/query"),
+            createServletHandler(new ServicesServlet(ServicesServlet.PLUGIN), "/management/plugins/"),
+            createServletHandler(new AETitleServlet(), "/management/settings/dicom"),
+            createServletHandler(new WebUIServlet(), "/webui"),
+            createWebUIModuleServletHandler(),
+            createServletHandler(new LoggerServlet(), "/logger"),
+            createServletHandler(new RunningTasksServlet(), "/index/task"),
+            createServletHandler(new ExportServlet(ExportType.EXPORT_CVS), "/export/cvs"),
+            createServletHandler(new ExportServlet(ExportType.LIST), "/export/list"),
+            createServletHandler(new ServerStorageServlet(), "/management/settings/storage/dicom"),
+            webpages
+        };
+
+        // setup the server
+        server = new Server(port);
+        // register the handlers on the server
+        this.contextHandlers = new ContextHandlerCollection();
+        this.contextHandlers.setHandlers(handlers);
+        server.setHandler(this.contextHandlers);
+        
+        // and then start the server
+        server.start();
+    }
+
+    private ServletContextHandler createWebUIModuleServletHandler() {
+        ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); // servlet with session support enabled
+        handler.setContextPath(CONTEXTPATH);
+
+        HttpServlet servletModule = new WebUIModuleServlet();
+        // CORS support
+        this.addCORSFilter(handler);
+        // Caching!
+        FilterHolder cacheHolder = new FilterHolder(new AbstractCacheFilter() {
+            @Override
+            protected String etag(HttpServletRequest req) {
+                String name = req.getRequestURI().substring("/webui/module/".length());
+                WebUIPlugin plugin = PluginController.getInstance().getWebUIPlugin(name);
+                if (plugin == null) return null;
+                if (WebUIModuleServlet.isPrerelease(plugin.getVersion())) {
+                    // pre-release, use hash (to facilitate development)
+                    String fingerprint = PluginController.getInstance().getWebUIModuleJS(name);
+                    return '"' + Md5Crypt.md5Crypt(fingerprint.getBytes()) + '"';
+                } else {
+                    // normal release, use weak ETag
+                    String pProcess = req.getParameter("process");
+                    boolean process = pProcess == null || Boolean.parseBoolean(pProcess);
+                    if (process) {
+                        return "W/\"" + plugin.getName() + '@' + plugin.getVersion() + '"';
+                    } else {
+                        return "W/\"" + plugin.getName() + '@' + plugin.getVersion() + ";raw\"";
+                    }
+                }
+            }
+        });
+        cacheHolder.setInitParameter(AbstractCacheFilter.CACHE_CONTROL_PARAM, "private, max-age=2592000"); // cache for 30 days
+        handler.addFilter(cacheHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
+        handler.addServlet(new ServletHolder(servletModule), "/webui/module/*");
+        return handler;
+    }
+
+    private ServletContextHandler createServletHandler(HttpServlet servlet, String path){
+        ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS); // servlet with session support enabled
+        handler.setContextPath(CONTEXTPATH);
+        
+        // CORS support
+        this.addCORSFilter(handler);
+
+        handler.addServlet(new ServletHolder(servlet), path);
+        return handler;
+    }
+
+    private void addCORSFilter(ServletContextHandler handler) {
+        String origins = ServerSettings.getInstance().getWeb().getAllowedOrigins();
+        if (origins != null) {
+            handler.setDisplayName("cross-origin");
+            FilterHolder corsHolder = new FilterHolder(CORSFilter.class);
+            corsHolder.setInitParameter(CORSFilter.ALLOWED_ORIGINS_PARAM, origins);
+            corsHolder.setInitParameter(CORSFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD,PUT,DELETE");
+            corsHolder.setInitParameter(CORSFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,Authorization,Content-Length");
+            handler.addFilter(corsHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
+        }
+    }
+
+    private void addCORSFilter(Handler handler) {
+        String origins = ServerSettings.getInstance().getWeb().getAllowedOrigins();
+        if (origins == null) {
+            return;
+        }
+
+        logger.debug("Applying CORS filter to {}", handler);
+        if (handler instanceof ServletContextHandler) {
+            ServletContextHandler svHandler = (ServletContextHandler)handler;
+            this.addCORSFilter(svHandler);
+            logger.debug("Applied CORS filter to {}!", svHandler);
+        } else if (handler instanceof HandlerWrapper) {
+            for (Handler h : ((HandlerWrapper)handler).getHandlers()) {
+                addCORSFilter(h);
+            }
+        } else if (handler instanceof HandlerCollection) {
+            for (Handler h : ((HandlerCollection)handler).getHandlers()) {
+                addCORSFilter(h);
+            }
+        }
+    }
+
+    /**
+     * Stops the Dicoogle Web service.
+     * @throws java.lang.Exception if a problem occurs when stopping the server
+     */
+    public void stop() throws Exception {
+        // abort if the server is not running
+        if (server == null) {
+            return;
+        }
+
+        try {
+            // stop the server
+            server.stop();
+
+            // voiding its value
+            server = null;
+        } finally {
+
+            // and remove the local cache, if any
+            if (cache != null) {
+                cache.terminate();
+                cache = null;
+            }
+        }
+        
+        this.pluginHandler = null;
+    }
+
+    public void addContextHandlers(HandlerList handler) {
+        this.contextHandlers.addHandler(handler);
+
+        this.addCORSFilter(handler);
+        //this.server.setHandler(this.contextHandlers);
+    }
+
+    public void stopPluginWebServices() {
+        if (this.pluginHandler != null) {
+            this.contextHandlers.removeHandler(this.pluginHandler);
+        }
+    }
+ 
+    public void stopLegacyWebServices() {
+        if (this.legacyHandler != null) {
+            this.contextHandlers.removeHandler(this.legacyHandler);
+        }
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/FirstResponserQueryHolder.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/FirstResponserQueryHolder.java
new file mode 100644
index 0000000..740d5a8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/FirstResponserQueryHolder.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+public class FirstResponserQueryHolder extends JointQueryTask {
+	
+	private Iterable<SearchResult> result;
+
+	@Override
+	public void onReceive(Task<Iterable<SearchResult>> e) {
+		try {
+			synchronized (this) {
+				if(result == null){
+					result = e.get();
+					stopAllTaks();
+				}
+			}
+
+			notifyAll();
+			
+		} catch (InterruptedException | ExecutionException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+	}
+
+	public FirstResponserQueryHolder(CountDownLatch latch) {
+		super();
+	}
+
+	private void stopAllTaks() {
+		this.cancel(true);
+	}
+
+	@Override
+	public void onCompletion() {
+		// TODO: MAY BE BUGGED
+		notifyAll();
+	}
+	
+	public Iterable<SearchResult> getResult() {
+		synchronized (this) {
+			while( !(this.isCancelled() || this.isDone())){
+				if(result != null)
+					return result;
+				
+				try {
+					wait();
+				} catch (InterruptedException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		}
+		return null;
+	}
+
+
+	
+	
+
+	
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/PluginsServlet.java.orig b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/PluginsServlet.java.orig
new file mode 100644
index 0000000..6088312
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/PluginsServlet.java.orig
@@ -0,0 +1,116 @@
+package pt.ua.dicoogle.server.web;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.GenericPluginInterface;
+import dicoogle.experimental.ExportsHttpData;
+import dicoogle.experimental.ExportsHttpPage;
+import dicoogle.experimental.HookPointAction;
+
+/**
+ * Handles the requests for plugins data and pages.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class PluginsServlet extends HttpServlet
+{
+	private HashMap<String, HookPointAction[]> hooks;
+
+	/**
+	 * Creates a plugin services servlet.
+	 *
+	 * @param hooks the global array of hooks for all the plugins and embeded services.
+	 */
+	public PluginsServlet(HashMap<String, HookPointAction[]> hooks)
+	{
+		this.hooks = hooks;
+	}
+
+	@Override
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
+	{
+		// FIXME should the process of performing requests for plugins data and pages need authentication? maybe each one can have a flag or something
+
+		String pluginName = ""; // the URLEncoded name of the plugin requested
+		String method = "data"; // the method requested: data, xslt or pages
+
+		// get the plugin and information requested
+		String tmp = request.getPathInfo();
+		if (tmp != null)
+		{
+			String[] parts = tmp.split("/");
+
+			if (parts.length > 1)
+				pluginName = parts[1]; // the URLEncoded name of the plugin requested
+			if (parts.length > 2)
+				method = parts[2]; // the method requested: data, xslt or pages
+		}
+
+		// check for the required plugin
+		GenericPluginInterface plugin = PluginController.getInstance().getPluginFromName(pluginName);
+		if (plugin == null)
+		{
+			response.sendError(HttpServletResponse.SC_NOT_FOUND, "Plugin not found!");
+			return;
+		}
+
+		// check if the plugin is running
+		if (! plugin.isRunning())
+		{
+			response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "The plugin is not running!");
+			return;
+		}
+
+		// check for data request
+		if (method.equalsIgnoreCase("data"))
+		{
+			// check if the plugin has the method
+			if (plugin instanceof ExportsHttpData)
+			{
+				((ExportsHttpData) plugin).getData(request, response);
+				return;
+			}
+
+			// plugins does not provide method
+			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "The plugin lacks the required method!");
+			return;
+		}
+
+		// check for xslt request
+		if (method.equalsIgnoreCase("xslt"))
+		{
+			// check if the plugin has the method
+			if (plugin instanceof ExportsHttpData)
+			{
+				((ExportsHttpData) plugin).getXSLT(request, response);
+				return;
+			}
+
+			// plugins does not provide method
+			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "The plugin lacks the required method!");
+			return;
+		}
+
+		// check for page request
+		if (method.equalsIgnoreCase("page"))
+		{
+			// check if the plugin has the method
+			if (plugin instanceof ExportsHttpData)
+			{
+				((ExportsHttpPage) plugin).getPage(request, response, hooks);
+				return;
+			}
+
+			// plugins does not provide method
+			response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "The plugin lacks the required method!");
+			return;
+		}
+
+		// no valid method used
+		response.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Invalid method requested!");
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Authentication.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Authentication.java
new file mode 100644
index 0000000..18cf4ab
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Authentication.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.auth;
+
+import pt.ua.dicoogle.server.users.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Provides login routines for users.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Authentication
+{
+	private static Authentication instance = null;
+	private final UsersStruct users;
+
+	private final Map<String, String> usersToken = new HashMap<>();
+	private final Map<String, String> tokenUsers = new HashMap<>();
+
+	private Authentication()
+	{
+		RolesXML rolesXML = new RolesXML();
+		RolesStruct rolesStruct = rolesXML.getXML();
+		// init the user list, if it wasn't done yet
+		UsersXML usersXML = new UsersXML();
+		usersXML.getXML();
+
+		// gets the instance of the user list
+		users = UsersStruct.getInstance();
+	}
+
+	/**
+	 * Returns the current instance of the authentication singleton.
+	 *
+	 * @return the current instance of the authentication singleton.
+	 */
+	public static synchronized Authentication getInstance()
+	{
+		if (instance == null)
+			instance = new Authentication();
+
+		return instance;
+	}
+
+
+	public User getUsername(String token)
+	{
+		String user = tokenUsers.get(token);
+		if (user==null)
+			return null;
+		return UsersStruct.getInstance().getUser(user);
+
+	}
+
+	public void logout(String token){
+		String user = tokenUsers.get(token);
+		String ntoken = usersToken.get(user);
+		tokenUsers.remove(ntoken);
+		usersToken.remove(user);
+
+	}
+
+	/**
+	 * Attempts to login on the platform.
+	 *
+	 * @param username the user name of the user to login.
+	 * @param password the clear text password of the user.
+	 * @return a Login object if successful login, null otherwise.
+	 */
+	public LoggedIn login(String username, String password)
+	{
+		// must have both username and password
+		if ((username == null) || (password == null))
+			return null;
+
+		// check if the user exists in the user list
+		User user = users.getUser(username);
+		if (user == null)
+			return null;
+
+		// calculate the supplied passwords hash and see if it matches the users
+		String passwordHash = HashService.getSHA1Hash(password);
+		if (! user.verifyPassword(passwordHash))
+			return null;
+		LoggedIn in = new LoggedIn(username, user.isAdmin());
+		if (usersToken.containsKey(username))
+			in.setToken(usersToken.get(username));
+
+		else {
+			String token  =UUID.randomUUID().toString();
+			usersToken.put(username, token);
+			tokenUsers.put(token, username);
+			in.setToken(usersToken.get(username));
+		}
+		// return a successfull login object
+		return in;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedIn.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedIn.java
new file mode 100644
index 0000000..b76e4f5
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedIn.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.auth;
+
+/**
+ * Maintains information about a users login.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class LoggedIn
+{
+	private String userName;
+	private boolean admin;
+	private String token;
+
+	public LoggedIn(String userName, boolean isAdmin)
+	{
+		this.userName = userName;
+		this.admin = isAdmin;
+	}
+
+	/**
+	 * @return the user name
+	 */
+	public String getUserName()
+	{
+		return userName;
+	}
+
+	/**
+	 * @return if this user is admin
+	 */
+	public boolean isAdmin()
+	{
+		return admin;
+	}
+
+	public String getToken() {
+		return token;
+	}
+
+	public void setToken(String token) {
+		this.token = token;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedInStatus.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedInStatus.java
new file mode 100644
index 0000000..1a7b8e2
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/LoggedInStatus.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.auth;
+
+/**
+ * A wrapper for the LogggedIn objects that are used on webapps.
+ * Holds the LoggedIn object and a status of why the LoggedIn object has the current value.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class LoggedInStatus
+{
+	public static int S_NOINFORMATION = 0;
+	public static int S_INVALIDCREDENTIALS = 1;
+	public static int S_UNAUTHORIZEDACCESS = 2;
+	public static int S_ALREADYLOGGEDIN = 3;
+	public static int S_VALIDLOGIN = 4;
+
+	private LoggedIn login;
+	private int status;
+
+	public LoggedInStatus()
+	{
+		this.login = null;
+		this.status = S_NOINFORMATION;
+	}
+
+	public LoggedInStatus(LoggedIn login, int status)
+	{
+		this.login = login;
+		this.status = status;
+	}
+
+	/**
+	 * @return the login
+	 */
+	public LoggedIn getLogin()
+	{
+		return login;
+	}
+
+	/**
+	 * @return the status
+	 */
+	public int getStatus()
+	{
+		return status;
+	}
+
+	public boolean wasAlreadyLoggedIn()
+	{
+		return (status == S_ALREADYLOGGEDIN);
+	}
+
+	public boolean noInformationSupplied()
+	{
+		return (status == S_NOINFORMATION);
+	}
+
+	public boolean invalidCredentialsSupplied()
+	{
+		return (status == S_INVALIDCREDENTIALS);
+	}
+
+	public boolean loggedInSuccessfully()
+	{
+		return (status == S_VALIDLOGIN);
+	}
+
+	public boolean unAuthorizedAccess()
+	{
+		return (status == S_UNAUTHORIZEDACCESS);
+	}
+
+	public boolean isCurrentlyLoggedIn()
+	{
+		return (((status == S_ALREADYLOGGEDIN) || (status == S_VALIDLOGIN)) && (login != null));
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Session.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Session.java
new file mode 100644
index 0000000..308cb24
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/auth/Session.java
@@ -0,0 +1,289 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.auth;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Handles and manages login requests and the information associated with it.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Session
+{
+	/**
+	 * Attemps to login using the supplied params.
+	 *
+	 * @param username the user name.
+	 * @param password the users password.
+	 * @return true if the login is successfull, false otherwise.
+	 */
+	public static boolean isSuccessfulLogin(String username, String password)
+	{
+		LoggedIn result = getSuccessfulLogin(username, password);
+
+		return (result != null);
+	}
+
+	/**
+	 * Attemps to login using the supplied params.
+	 *
+	 * @param username the user name.
+	 * @param password the users password.
+	 * @return a LoggedIn object if the login is successfull, null otherwise.
+	 */
+	public static LoggedIn getSuccessfulLogin(String username, String password)
+	{
+		Authentication auth = Authentication.getInstance();
+		LoggedIn result = auth.login(username, password);
+
+		return result;
+	}
+
+	/**
+	 * Check if there is a user logged in on the session supplied.
+	 *
+	 * @param session the HttpSession object of the request.
+	 * @return true if there is a user logged in on the session supplied, false otherwise.
+	 */
+	public static boolean isUserLoggedIn(HttpSession session)
+	{
+		return (getUserLoggedIn(session) != null);
+	}
+
+	/**
+	 * Check if there is a user logged in on the session supplied and if (s)he ia an administrator.
+	 *
+	 * @param session the HttpSession object of the request.
+	 * @return true if there is a user logged in on the session supplied and is an administrator, false otherwise.
+	 */
+	public static boolean isUserLoggedInAnAdmin(HttpSession session)
+	{
+		LoggedIn login = getUserLoggedIn(session);
+		return ((login != null) && (login.isAdmin()));
+	}
+
+	/**
+	 * Gets the LoggedIn object that has the information relative to user logged in on the session supplied.
+	 *
+	 * @param session the HttpSession object of the request.
+	 * @return a LoggedIn object if there is a user logged in on the session supplied, null otherwise.
+	 */
+	public static LoggedIn getUserLoggedIn(HttpSession session)
+	{
+		// if the sessio is invalid
+		if (session == null)
+			return null;
+
+		// if the client is not yet aware of (or didn't aceepted/joined) the session
+		if (session.isNew())
+			return null;
+
+		// if no login information was found
+		Object login = session.getAttribute("login");
+		if (login == null)
+			return null;
+
+		// the client is currently logged in
+		return (LoggedIn) login;
+	}
+
+	/**
+	 * If there is a user logged in on the current HttpSession, log out.
+	 *
+	 * @param session the HttpSession object of the request.
+	 * @return if there was a logout action performed or not.
+	 */
+	public static boolean logout(HttpServletRequest request)
+	{
+		HttpSession session = request.getSession(false);
+		try
+		{
+			session.invalidate();
+		}
+		catch (Exception e )
+		{
+			System.err.println("Tracking session");
+		}
+
+
+
+		// if the sessio is invalid
+		if (session == null)
+			return false;
+
+		// if the client is not yet aware of (or didn't aceepted/joined) the session
+		if (session.isNew())
+			return false;
+
+		// if no login information was found
+		Object login = session.getAttribute("login");
+		if (login == null)
+			return false;
+
+		// the client is currently logged in, so logout
+		session.removeAttribute("login");
+		session.invalidate();
+		return true;
+	}
+
+	/**
+	 * Checks if the request made to a servlet was made by a logged is user,
+	 * or if the request carries the required login information.
+	 * <br>
+	 * This is done by first checking if the request has a valid
+	 * (with valid login information) session (like an AJAX request from a
+	 * cookies enabled browser), if not checks if the request parameters
+	 * have valid login information (like made a REST[less] stand-alone
+	 * application), and if none of the above situations happened send an
+	 * adequate response to the client.
+	 *
+	 * @param requiresAdminRights if the current request requires admin rights to be served/performed.
+	 * @return a LoggedIn object if the request is to be served, null otherwise.
+	 */
+	public static LoggedIn servletLogin(HttpServletRequest request, HttpServletResponse response, boolean requiresAdminRights) throws IOException
+	{
+		// check if there a session and a login information attached to it
+		HttpSession session = request.getSession(false);
+		LoggedIn login = getUserLoggedIn(session);
+		if (login != null)
+		{
+			// check if this request needs admin rights and the user has them
+			if (requiresAdminRights)
+			{
+				if (login.isAdmin())
+					return login;
+				else
+				{
+					response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Administrator rights are needed to process this request!");
+					return null;
+				}
+			}
+			else
+				return login;
+		}
+
+		// since the above failed, check if there is valid login information on the request parameters
+		String username = request.getParameter("username");
+		String password = request.getParameter("password");
+		login = getSuccessfulLogin(username, password);
+		if (login != null)
+		{
+			// check if this request needs admin rights and the user has them
+			if (requiresAdminRights)
+			{
+				if (login.isAdmin())
+					return login;
+				else
+				{
+					response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Administrator rights are needed to process this request!");
+					return null;
+				}
+			}
+			else
+				return login;
+		}
+
+		// both situations failed
+		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "No login information found!");
+		return null;
+	}
+
+	/**
+	 * Checks if the request made to a webapp was made by a logged is user,
+	 * or if the request carries the required login information.
+	 * <br>
+	 * This is done by first checking if the request has a valid
+	 * (with valid login information) session (like an AJAX request from a
+	 * cookies enabled browser), if not checks if the request parameters
+	 * have valid login information (like made a REST[less] stand-alone
+	 * application), and if none of the above situations happened send an
+	 * adequate response to the client, on most cases a redirection to the
+	 * login page will be sent.
+	 *
+	 * @param requiresAdminRights if the current request requires admin rights to be served/performed.
+	 * @return a LoggedIn object if the request is to be served, null otherwise.
+	 */
+	public static LoggedInStatus webappLogin(HttpServletRequest request, HttpServletResponse response, boolean requiresAdminRights) throws IOException
+	{
+		// check if there a session and a login information attached to it
+		//HttpSession session = request.getSession(true);
+		//LoggedIn login = getUserLoggedIn(session);
+		/*if (login != null)
+		{
+			// check if this request needs admin rights and the user has them
+			if (requiresAdminRights && (! login.isAdmin()))
+			{
+				response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+				return new LoggedInStatus(null, LoggedInStatus.S_UNAUTHORIZEDACCESS);
+			}
+
+			return new LoggedInStatus(login, LoggedInStatus.S_ALREADYLOGGEDIN);
+		}*/
+
+		// since the above failed, check if there is valid login information on the request parameters
+		String username = request.getParameter("username");
+		String password = request.getParameter("password");
+		LoggedIn login = getSuccessfulLogin(username, password);
+		if (login != null)
+		{
+			// check if this request needs admin rights and the user has them
+			if (requiresAdminRights && (! login.isAdmin()))
+			{
+				response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+				return new LoggedInStatus(null, LoggedInStatus.S_UNAUTHORIZEDACCESS);
+			}
+
+			// add the login information to the session
+			HttpSession session = request.getSession(true); // force the creation of a new session if there is none
+			session.setAttribute("login", login);
+			return new LoggedInStatus(login, LoggedInStatus.S_VALIDLOGIN);
+		}
+
+		// both situations failed
+		if ((username == null) && (password == null))
+			return new LoggedInStatus(null, LoggedInStatus.S_NOINFORMATION);
+		else
+			return new LoggedInStatus(null, LoggedInStatus.S_INVALIDCREDENTIALS);
+	}
+
+	/**
+	 * Based on the request referer returns the address of the previously visited
+	 * page or to the default main page if none.
+	 *
+	 * @param request the original http request object.
+	 * @return a string containing the previous URL.
+	 */
+	public static String getLastVisitedURL(HttpServletRequest request)
+	{
+		String result = "/index.jsp";
+
+		if (request == null)
+			return result;
+
+		result = request.getHeader("Referer");
+		if (result == null)
+			result = "/index.jsp";
+
+		return result;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Convert2PNG.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Convert2PNG.java
new file mode 100644
index 0000000..40ccf7d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Convert2PNG.java
@@ -0,0 +1,391 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.dicom;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.ImageWriter;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+
+import org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam;
+
+import pt.ua.dicoogle.sdk.StorageInputStream;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.server.web.utils.ImageLoader;
+
+/**
+ * Handles conversion between the images (formats) found inside a DICOM file
+ * and the PNG image format, for proper lossless web view.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class Convert2PNG
+{	
+    private static final Logger logger = LoggerFactory.getLogger(Convert2PNG.class);
+    
+    private synchronized static ImageReader createDICOMImageReader() {
+        Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("DICOM"); // gets the first registered ImageReader that can read DICOM data
+        
+        ImageReader sReader = it.next();
+        return sReader;
+    }
+    
+    private synchronized static ImageWriter createPNGImageWriter() {
+        Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName("PNG"); // gets the first registered ImageWriter that can write PNG data
+        
+        ImageWriter sWriter = it.next();
+        return sWriter;
+    }
+    
+	// Transformations that can be applied on each conversion.
+	/**
+	 * No transform applied.
+	 */
+    @Deprecated
+	public static final int TRANSFORM_NONE = 0;
+	/**
+	 * Scale image based on a width target.
+	 */
+    @Deprecated
+	public static final int TRANSFORM_SCALE_BY_WIDTH = 1;
+	/**
+	 * Scale image based on a height target.
+	 */
+    @Deprecated
+	public static final int TRANSFORM_SCALE_BY_HEIGHT = 2;
+	/**
+	 * Scale image based on a percentage value.
+	 */
+    @Deprecated
+	public static final int TRANSFORM_SCALE_BY_PERCENT = 3;
+        
+	/**
+	 * Reads an input DICOM file, applies a transformation to it if any, and returns
+     * the desired frame as a PNG-encoded memory stream.
+	 *
+	 * @param dcmStream The Dicoogle storage input Stream for the DICOM File.
+	 * @param frameIndex the index of the frame wanted (zero based).
+	 * @param transformType the transform to execute.
+	 * @param transformParam1 the param used on width and height based scales.
+	 * @param transformParam2 the param used on percentage based scales.
+	 * @return the frame encoded in a PNG memory stream.
+	 */
+    @Deprecated
+	public static ByteArrayOutputStream DICOM2PNGStream(StorageInputStream dcmStream, int frameIndex, int transformType, int transformParam1, float transformParam2)
+	{	
+		// setup the DICOM reader
+        ImageReader reader = createDICOMImageReader();                
+		if (reader == null) // if no valid reader was found abort
+			return null;
+		
+		DicomImageReadParam readParams = (DicomImageReadParam) reader.getDefaultReadParam(); // and set the default params for it (height, weight, alpha) // FIXME is this even needed?
+		
+		// setup the PNG writer
+		ImageWriter writer = createPNGImageWriter(); // gets the first registered ImageWriter that can save PNG data
+		if (writer == null) // if no valid writer was found abort
+			return null;
+
+		ImageWriteParam writeParams = writer.getDefaultWriteParam(); // and set the default params for it (height, weight, alpha)
+//		writeParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // activate PNG compression to save on bandwidth
+//		writeParams.setCompressionType("Deflater"); // overall best compressor for black and white pictures
+//		writeParams.setCompressionQuality(0.0F); // best compression ratio (but longer [de]compression time)
+// NOTE the above compression params are not currently needed because ImageIO already automatically compresses PNG by default, it's depicted on http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4829970 as a bug but it's more of a "can't set the compression level" problem as it uses the Deflater.BEST_COMPRESSION as default (see line 144 of com.sun.imageio.plugins.png.PNGImageWriter), the code remains comment so if in the future ImageIO allows for compression level set we can set it to th [...]
+		writeParams.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // activate progressive mode (adam7), best for low bandwidth connections
+		
+		try
+		{			
+			ImageInputStream inStream = ImageIO.createImageInputStream(dcmStream.getInputStream());
+
+			reader.setInput(inStream);
+			
+			// make sure that we will read a frame within bounds
+			int frameCount = reader.getNumImages(true); // get the number of avalable frame in the DICOM file
+			if ((frameCount < 1) || (frameIndex < 0) || (frameIndex >= frameCount)) // if teither the file has no frames or the frame wanted is outside of bounds abort
+				return null;
+
+			// read the specified frame from the file
+			BufferedImage image = reader.read(frameIndex, readParams);
+			
+			inStream.close();
+			
+
+			// if no frame was read abort
+			if (image == null)
+				return null;
+			
+			// if there is a transform to be applied to the image, this is the right place to do it
+			switch (transformType)
+			{
+				case TRANSFORM_SCALE_BY_WIDTH:
+					image = scaleImageByWidth(image, transformParam1);
+				break;
+				case TRANSFORM_SCALE_BY_HEIGHT:
+					image = scaleImageByHeight(image, transformParam1);
+				break;
+				case TRANSFORM_SCALE_BY_PERCENT:
+					image = scaleImageByPercent(image, transformParam2);
+				break;
+			}
+			// mount the resulting memory stream
+			ByteArrayOutputStream result = new ByteArrayOutputStream();
+
+			// write the specified frame to the resulting stream
+			ImageOutputStream outStream = ImageIO.createImageOutputStream(result);
+			writer.setOutput(outStream);
+			writer.write(image);
+			outStream.close();
+						
+			return result;
+		}
+		catch (IOException e)
+		{
+			System.out.println("\nError: couldn't read dicom image!" + e.getMessage());
+			return null;
+		}
+	}
+
+	/**
+	 * Reads an input DICOM file and returns the desired frame as a PNG-encoded memory stream.
+	 *
+	 * @param dcmStream The Dicoogle storage input Stream for the DICOM File.
+	 * @param frameIndex the index of the frame wanted (starting with #0).
+	 * @return the frame encoded in a PNG memory stream.
+     * @throws IOException if the I/O operations on the images fail
+	 */
+	public static ByteArrayOutputStream DICOM2PNGStream(StorageInputStream dcmStream, int frameIndex) throws IOException {
+        return DICOM2PNGStream(dcmStream.getInputStream(), frameIndex);
+	}
+
+    /**
+	 * Reads an input DICOM file and returns the desired frame as a PNG-encoded memory stream.
+	 *
+	 * @param iStream an input stream for the DICOM File.
+	 * @param frameIndex the index of the frame wanted (starting with #0).
+	 * @return the frame encoded in a PNG memory stream.
+     * @throws IOException if the I/O operations on the images fail
+	 */
+	public static ByteArrayOutputStream DICOM2PNGStream(InputStream iStream, int frameIndex) throws IOException {
+		// setup the PNG writer
+		ImageWriter writer = createPNGImageWriter();
+
+		ImageWriteParam writeParams = writer.getDefaultWriteParam(); // and set the default params for it (height, weight, alpha)
+		writeParams.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // activate progressive mode (adam7), best for low bandwidth connections
+		
+        BufferedImage image = ImageLoader.loadImage(iStream);
+
+        // mount the resulting memory stream
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+
+        // write the specified frame to the resulting stream
+        try (ImageOutputStream outStream = ImageIO.createImageOutputStream(result)) {
+            writer.setOutput(outStream);
+            writer.write(image);
+        }
+
+        return result;
+	}
+
+	/**
+	 * Reads an input DICOM file, scales it to fit in the given dimensions and returns the
+     * desired frame as a PNG-encoded memory stream.
+	 *
+	 * @param inStream The Dicoogle storage input Stream for the DICOM File.
+	 * @param frameIndex the index of the frame wanted (starting with #0).
+     * @param width the maximum width of the resulting image
+     * @param height the maximum height of the resulting image
+	 * @return the frame encoded in a PNG memory stream.
+     * @throws IOException if the I/O operations on the images fail
+	 */
+	public static ByteArrayOutputStream DICOM2ScaledPNGStream(InputStream inStream, int frameIndex, int width, int height) throws IOException {
+        if (inStream == null) {
+            throw new NullPointerException("dcmStream");
+        }
+        if (frameIndex < 0) {
+            throw new IllegalArgumentException("bad frameIndex");
+        }
+        if (width <= 0) {
+            throw new IllegalArgumentException("bad width");
+        }
+        if (height <= 0) {
+            throw new IllegalArgumentException("bad height");
+        }
+        
+		// setup the PNG writer
+        BufferedImage image = ImageLoader.loadImage(inStream);
+        
+        image = scaleImage(image, width, height);
+
+        // mount the resulting memory stream
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+
+        // write the specified frame to the resulting stream
+        try (ImageOutputStream outStream = ImageIO.createImageOutputStream(result)) {
+            ImageWriter writer = createPNGImageWriter();
+            ImageWriteParam writeParams = writer.getDefaultWriteParam(); // and set the default params for it
+            writeParams.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // activate progressive mode (adam7), best for low bandwidth connections
+            writer.setOutput(outStream);
+            writer.write(image);
+        }
+
+        return result;
+	}
+
+	/**
+	 * Reads an input DICOM file, scales it to fit in the given dimensions and returns the
+     * desired frame as a PNG-encoded memory stream.
+	 *
+	 * @param dcmStream The Dicoogle storage input Stream for the DICOM File.
+	 * @param frameIndex the index of the frame wanted (starting with #0).
+     * @param width the maximum width of the resulting image
+     * @param height the maximum height of the resulting image
+	 * @return the frame encoded in a PNG memory stream.
+     * @throws IOException if the I/O operations on the images fail
+	 */
+	public static ByteArrayOutputStream DICOM2ScaledPNGStream(StorageInputStream dcmStream, int frameIndex, int width, int height) throws IOException {
+        return DICOM2ScaledPNGStream(dcmStream.getInputStream(), frameIndex, width, height);
+	}
+    
+	/**
+	 * Retrieve the number of frames from an input DICOM file.
+	 *
+	 * @param dcmFile The Dicoogle storage input Stream for the DICOM File.
+	 * @return an integer representing the number of frames in the image,
+     *   or <tt>-1</tt> if the operation fails
+	 */
+	public static int getNumberOfFrames(StorageInputStream dcmFile)
+	{	
+		// setup the DICOM reader
+        ImageReader reader = createDICOMImageReader();                
+	
+		try (ImageInputStream inStream = ImageIO.createImageInputStream(dcmFile.getInputStream())) {
+
+			reader.setInput(inStream);
+			
+			// make sure that we will read a frame within bounds
+			int frameCount = reader.getNumImages(true); 
+
+			return frameCount;
+
+		} catch (IOException e) {
+            logger.error("Failed to read DICOM image", e);
+		}
+		return -1;
+	}
+
+	/**
+	 * Resize a BufferedImage to the specified width, preserving the original image aspect ratio.
+	 *
+	 * @param image the original image to scale.
+	 * @param width the target width.
+	 * @return a BufferedImage scaled to the target width.
+	 */
+	public static BufferedImage scaleImageByWidth(BufferedImage image, int width)
+	{
+		if (width <= 0)
+			return image;
+
+		Image scaledImage = image.getScaledInstance(width, -1, Image.SCALE_SMOOTH); // scale the input, smooth scaled
+		BufferedImage result = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_INT_RGB); // create the output image
+
+		result.getGraphics().drawImage(scaledImage, 0, 0, null); // draw the scaled image onto the output
+
+		return result;
+	}
+
+	/**
+	 * Resize a BufferedImage to the specified height, preserving the original image aspect ratio.
+	 *
+	 * @param image the original image to scale.
+	 * @param height the target height.
+	 * @return a BufferedImage scaled to the target height.
+	 */
+	public static BufferedImage scaleImageByHeight(BufferedImage image, int height)
+	{
+		if (height <= 0)
+			return image;
+
+		Image scaledImage = image.getScaledInstance(-1, height, Image.SCALE_SMOOTH); // scale the input, smooth scaled
+		BufferedImage result = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_INT_RGB); // create the output image
+		result.getGraphics().drawImage(scaledImage, 0, 0, null); // draw the scaled image onto the output
+
+		return result;
+	}
+
+	/**
+	 * Resize a BufferedImage based on the specified percentage, preserving the original image aspect ratio.
+	 *
+	 * @param image the original image to scale.
+	 * @param percent the percentage to scale to, 1.0 is original, 0.5 is half, 2.0 is double, etc.
+	 * @return a BufferedImage scaled to the target percentage.
+	 */
+	public static BufferedImage scaleImageByPercent(BufferedImage image, float percent)
+	{
+		if ((percent <= 0.0F) || (percent == 1.0F)) // if the scale is either null, negative or none at all return the original image
+			return image;
+
+		Image scaledImage = image.getScaledInstance((int) (percent * image.getWidth()), -1, Image.SCALE_SMOOTH); // scale the input, smooth scaled
+		BufferedImage result = new BufferedImage(scaledImage.getWidth(null), scaledImage.getHeight(null), BufferedImage.TYPE_INT_RGB); // create the output image
+
+		result.getGraphics().drawImage(scaledImage, 0, 0, null); // draw the scaled image onto the output
+
+		return result;
+	}
+
+    /**
+	 * Resize a BufferedImage to fit the specified dimensions, while preserving the original image aspect ratio.
+     * The image scaling procedure will guarantee that at least one of the dimensions will be equal to
+     * the maximum target.
+	 *
+	 * @param image the original image to scale.
+	 * @param width the maximum width of the target
+	 * @param height the maximum height of the target
+	 * @return a copy of the image, scaled to fit into the given dimensions
+     * @throws IllegalArgumentException on bad width and height dimensions
+     * @throws NullPointerException on null image
+	 */
+	public static BufferedImage scaleImage(BufferedImage image, int width, int height)
+	{
+        if (image == null) {
+            throw new NullPointerException("image is null");
+        }
+		if (width <= 0) {
+            throw new IllegalArgumentException("illegal width dimension: " + width);
+        }
+		if (height <= 0) {
+            throw new IllegalArgumentException("illegal height dimension: " + height);
+        }
+        
+        if (width < height) {
+            return scaleImageByHeight(image, height);
+        } else {
+            return scaleImageByWidth(image, width);
+        }
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Information.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Information.java
new file mode 100644
index 0000000..d95378a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Information.java
@@ -0,0 +1,341 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.dicom;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+
+import com.google.common.base.CharMatcher;
+import java.util.List;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * Provides several helper functions for retrieving information about a DICOM file.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class Information
+{
+	/**
+	 * Based on a SOP Instance UID, returns a File handler for the respective .dcm file. This method
+     * issues all available query providers, see {@link Information#getFileFromSOPInstanceUID(java.lang.String, java.util.List)}
+     * to select specific providers
+	 *
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+	 * @return a File handler for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static StorageInputStream getFileFromSOPInstanceUID(String sopInstanceUID)
+	{
+        return getFileFromSOPInstanceUID(sopInstanceUID, null);
+	}
+
+    /**
+	 * Based on a SOP Instance UID, returns a Dicoogle storage file handle for the respective resource file.
+	 *
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+     * @param providers a list of query sources to issue the file handler (if null, all enabled providers are queried)
+	 * @return a File handler for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static StorageInputStream getFileFromSOPInstanceUID(String sopInstanceUID, List<String> providers)
+	{
+        System.err.printf("getFileFromSOPInstanceUID(%s, %s)\n", sopInstanceUID, providers);
+		if (sopInstanceUID == null)
+			return null;
+        
+        if (providers == null) {
+            providers = PluginController.getInstance().getQueryProvidersName(true);
+        }
+
+		String query = "SOPInstanceUID:" + sopInstanceUID;
+
+		CountDownLatch latch = new CountDownLatch(1);	
+		MyHolder holder= new MyHolder(latch);
+		PluginController.getInstance().query(holder, providers, query, new HashMap<String, String>());
+
+		try {
+			latch.await();
+		} catch (InterruptedException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+		
+		try {
+			latch.await();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+        return holder.getRet();
+	}
+	
+	private static class MyHolder extends JointQueryTask{
+		private StorageInputStream ret = null;
+		private CountDownLatch latch;		
+		
+		@Override
+		public void onReceive(Task<Iterable<SearchResult>> e) {
+			try {		
+				URI uri= null;
+				 Iterable<SearchResult> itResults = e.get();
+				 
+				 for(SearchResult r : itResults){
+			        	if(uri == null)
+			        		uri = r.getURI();
+			            System.out.println("URI: "+uri.toString());
+			        }
+			        
+			        if(uri != null){
+			        	StorageInterface str = PluginController.getInstance().getStorageForSchema(uri);
+			            if(str != null){
+			            	Iterable<StorageInputStream> stream = str.at(uri);
+			            	for( StorageInputStream r : stream){
+			            		ret = r;
+			            		
+			            		stopAllTaks();
+			            		
+			            		latch.countDown();
+			            		
+				            	return;
+				            }
+			            }
+			        }
+			} catch (InterruptedException | ExecutionException e1) {
+				// TODO Auto-generated catch block
+				e1.printStackTrace();
+			}
+		}
+		
+		public MyHolder(CountDownLatch latch) {
+			super();
+			this.latch = latch;
+		}
+
+		private void stopAllTaks() {
+			this.cancel(true);
+		}
+
+		@Override
+		public void onCompletion() {
+			latch.countDown();
+		}
+
+		public StorageInputStream getRet() {
+			return ret;
+		}
+	}
+	/**
+	 * Based on a SOP Instance UID returns a hash table containing all name and value tag pairs for the respective .dcm file.
+     * This method issues all available query providers, see {@link Information#getFileFromSOPInstanceUID(java.lang.String, java.util.List)}
+     * to select specific providers.
+	 *
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+	 * @return a Hashtables containing all name and value tag pairs for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static HashMap<String, Object> searchForFileIndexedMetaData(String sopInstanceUID)
+	{
+        return searchForFileIndexedMetaData(sopInstanceUID, null);
+    }
+
+	/**
+	 * Based on a SOP Instance UID returns a hash table containing all name and value tag pairs for the respective .dcm file.
+	 *
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+     * @param providers a list of query sources to issue the tables
+	 * @return a Hashtables containing all name and value tag pairs for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static HashMap<String, Object> searchForFileIndexedMetaData(String sopInstanceUID, List<String> providers) // XXX SOP Instance UID should always be set within a DICOM file, I think...
+	{
+		if (sopInstanceUID == null)
+			return null;
+        
+        if (providers == null) {
+            providers = PluginController.getInstance().getQueryProvidersName(true);
+        }
+
+		// add all those tags to the extra fields that will be retried on a search query
+		HashMap<String, String> extraFields = new HashMap<>();
+		// get all the tags that can possibly be used within the file
+		HashMap<String, Integer> allTags = DictionaryAccess.getInstance().getTagList();
+
+		for(String key : allTags.keySet()){
+			extraFields.put(key, null);
+		}
+		/*
+		HashMap<Integer, TagValue> mf = TagsStruct.getInstance().getManualFields();
+		for (Integer i : mf.keySet())
+		{
+			extraFields.put(mf.get(i).getAlias(), null);
+		}
+		HashMap<Integer, TagValue> df = TagsStruct.getInstance().getDimFields();
+		for (Integer i : df.keySet())
+		{
+			extraFields.put(df.get(i).getAlias(), null);
+		}*/
+
+		// build the query setring for the search
+		String query = "SOPInstanceUID:" + sopInstanceUID;
+
+		//execute search
+        Iterable<SearchResult> itResults = null;
+		try {
+			
+			JointQueryTask holder = new JointQueryTask() {
+				
+				@Override
+				public void onReceive(Task<Iterable<SearchResult>> e) {
+					// TODO Auto-generated method stub
+					
+				}
+				
+				@Override
+				public void onCompletion() {
+					// TODO Auto-generated method stub
+					
+				}
+			};
+			itResults = PluginController.getInstance().query(holder, providers, query, extraFields).get();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		} catch (ExecutionException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		if(itResults == null)
+			return null;
+		
+		HashMap<String, Object> ret = new HashMap<>();
+		// return the first result (which should be the only one, by the way) extra fields (which contains all the tags and their values for this file)
+        for(SearchResult r : itResults){
+            ret.putAll(r.getExtraData());
+        }
+        return ret;//no results
+    }
+
+	private static final char start = 0;
+	private static final char end = 31;
+
+   	/**
+	 * Based on a SOP Instance UID returns a String containing a XML document filled with all name and value tag pairs for the respective .dcm file.
+	 * This method will query all enabled sources.
+     * 
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+	 * @return a String containing a XML document filled with all name and value tag pairs for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static String getXMLTagListFromFile(String sopInstanceUID) {
+        return getXMLTagListFromFile(sopInstanceUID, null);
+    }
+
+    /**
+	 * Based on a SOP Instance UID returns a String containing a XML document filled with all name and value tag pairs for the respective .dcm file.
+	 *
+	 * @param sopInstanceUID a String containing a valid/indexed SOP Instance UID.
+     * @param providers a list of query sources to issue the document
+	 * @return a String containing a XML document filled with all name and value tag pairs for the respective .dcm file if the SOP Instance UID is valid and indexed, null otherwise.
+	 */
+	public static String getXMLTagListFromFile(String sopInstanceUID, List<String> providers)
+	{
+		// get all the tags and their values present on the file
+		HashMap<String, Object> tags = searchForFileIndexedMetaData(sopInstanceUID, providers);
+		if (tags == null)
+		{
+			return null;
+		}
+
+		// create the XML string builder and open the xml document
+		StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+		xml.append("<tags>");
+		
+		Element rootElem = new Element("tags");
+		
+		// loop through all the tags set and add them and their values to the XML tree
+		Iterator<String> it = tags.keySet().iterator();
+		while (it.hasNext())
+		{
+			String key = it.next();
+			String value = (String) tags.get(key);
+			value = value.trim();
+			
+			value = CharMatcher.inRange(start, end).and(CharMatcher.noneOf("\t\r\n")).collapseFrom(value, ' ');
+			
+			Element tagElem = new Element("tag");
+			tagElem.setAttribute("name", key);
+			tagElem.setText(value);
+			
+			rootElem.addContent(tagElem);
+		}
+		
+		XMLOutputter outStream = new XMLOutputter(Format.getCompactFormat());
+		StringWriter wr = new StringWriter();
+		try {
+			outStream.output(new Document(rootElem), wr);
+		} catch (IOException e) {
+			return null;
+		}
+		
+		return wr.toString();
+	}
+
+	public static float getFrameRateFromImage(String sopUID){
+		HashMap<String, Object> tags = searchForFileIndexedMetaData(sopUID);
+		if(tags == null)
+			return 0;
+
+		for(String key : tags.keySet()){
+			System.out.println("Key: "+key+" Value: "+tags.get(key));
+		}
+		
+		if(tags.containsKey("RecommendedDisplayFrameRateInFloat"))
+			return Float.parseFloat("RecommendedDisplayFrameRateInFloat");
+		
+		if(tags.containsKey("RecommendedDisplayFrameRate"))
+			return Float.parseFloat("RecommendedDisplayFrameRate");
+		
+		return 0;
+	}
+	
+	public static int getNumberOfFramesInFile(String sopInstanceUID){
+		StorageInputStream dcmFile = Information.getFileFromSOPInstanceUID(sopInstanceUID);
+	
+		if(dcmFile == null)
+			return -1;
+		
+		return Convert2PNG.getNumberOfFrames(dcmFile);
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Search.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Search.java
new file mode 100644
index 0000000..8266f52
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/Search.java
@@ -0,0 +1,906 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.dicom;
+
+import static pt.ua.dicoogle.server.web.utils.Query.addExtraQueryParam;
+
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.settings.Utils;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * A simple class used by the Dicoogle Web interface that allow web users to
+ * have the same searching capabilities of desktop application users. 
+ * 
+ * The new version of these class generates the query tasks. These tasks take into
+ * account the multiple available providers. The search task is then placed in a SearchHolder
+ * especially created to the issuing user. This holder is accessible via /search/holders.
+ * 
+ * @author Tiago Marques Godinho
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Search {
+	private List<String> selectedProviders;
+
+	/**
+	 * Is this an advanced search?
+	 */
+	private boolean isAdvanced;
+
+	/**
+	 * Simple query string.
+	 */
+	private String simpleQuery;
+	/**
+	 * If the simple query string is keyword based.
+	 */
+	private boolean keyworded;
+
+	/**
+	 * How long did the search procedure take to complete, in milliseconds.
+	 */
+	private long timeTaken;
+
+	/**
+	 * Advanced search params.
+	 */
+	private String patientName;
+	private String patientID;
+	private String patientGender;
+	private String institutionName;
+	private String physician;
+	private String operatorName;
+	private String studyDateFormat;
+	private String exactDate;
+	private boolean useStartDate;
+	private boolean useEndDate;
+	private String startDate;
+	private String endDate;
+	private boolean modCR;
+	private boolean modMG;
+	private boolean modPT;
+	private boolean modXA;
+	private boolean modES;
+	private boolean modCT;
+	private boolean modMR;
+	private boolean modRF;
+	private boolean modUS;
+	private boolean modDX;
+	private boolean modNM;
+	private boolean modSC;
+	private boolean modOT;
+	private boolean modOthers;
+
+	/**
+	 * Final query string.
+	 */
+	private String finalQuery;
+
+	/**
+	 * Lists of search results in various forms.
+	 */
+	private Collection<SearchResult> searchResults;
+
+	/**
+	 * If the result list is supposed to have all the extra fields (servlet XML
+	 * request) or just the minimum (webapp search).
+	 */
+	private boolean fullRequest;
+
+	private HttpSession httpSession;
+
+	private int searchID;
+
+	@SuppressWarnings("unchecked")
+	public Search(ServletRequest request) {
+		this.searchID = -1;
+		// reset all the internal properties
+		isAdvanced = false;
+		simpleQuery = null;
+		patientName = null;
+		patientID = null;
+		patientGender = null;
+		institutionName = null;
+		physician = null;
+		operatorName = null;
+		studyDateFormat = null;
+		exactDate = null;
+		useStartDate = false;
+		useEndDate = false;
+		startDate = null;
+		endDate = null;
+		modCR = false;
+		modMG = false;
+		modPT = false;
+		modXA = false;
+		modES = false;
+		modCT = false;
+		modMR = false;
+		modRF = false;
+		modUS = false;
+		modDX = false;
+		modNM = false;
+		modSC = false;
+		modOT = false;
+		modOthers = false;
+		finalQuery = null;
+		searchResults = null;
+		fullRequest = false;
+
+		// this ensures that any special characters won't be parsed incorrectly
+		try {
+			request.setCharacterEncoding("UTF-8");
+		} catch (UnsupportedEncodingException ex) {
+			// do nothing
+		}
+
+		// get the query method (either default or advanced)
+		String method = request.getParameter("method");
+
+		// see if we should parse the request as simple or advanced search
+		if ((method != null) && (!method.isEmpty())) {
+			if (method.equalsIgnoreCase("Advanced")) // advanced search
+			{
+				isAdvanced = true;
+			}
+		}
+
+		// and now mount the proper query
+		if (isAdvanced) {
+			mountAdvancedSearch(request);
+		} else {
+			mountSimpleSearch(request);
+		}
+
+		String qp = request.getParameter("queryProviders");
+
+		System.out.println("QueryProviders: " + qp);
+		JSONArray arr = JSONArray.fromObject(qp);
+
+		System.out.println("QueryProviders: " + qp);
+		if (qp != null) {
+			this.selectedProviders = new ArrayList<>();
+			this.selectedProviders.addAll(JSONArray.toCollection(arr,
+					String.class));
+		} else {
+			this.selectedProviders = PluginController.getInstance()
+					.getQueryProvidersName(true);
+		}
+		this.httpSession = ((HttpServletRequest) request).getSession(false);
+	}
+
+	private void mountSimpleSearch(ServletRequest request) {
+		// get the only param of this simple query
+		simpleQuery = request.getParameter("query");
+		keyworded = Utils.parseCheckBoxValue(request.getParameter("keywords"));
+
+		// parse the user query into an expression
+		if ((simpleQuery != null) && (!simpleQuery.trim().isEmpty())) // if the
+																		// query
+																		// is
+																		// not
+																		// empty...
+		{
+			// ... build a query expression based on it and get its resulting
+			// query string
+			if (!isKeyworded()) {
+				// write the QueryString respecting BNF grammer defined
+				// regarding Lucene documentation 2.4.X branch
+				QueryExpressionBuilder exp = new QueryExpressionBuilder(
+						simpleQuery);
+				finalQuery = exp.getQueryString();
+			} else {
+				finalQuery = simpleQuery;
+			}
+		} else {
+			finalQuery = "*:*"; // default query string
+		}
+	}
+
+	private void mountAdvancedSearch(ServletRequest request) {
+		isAdvanced = true;
+
+		// get all the params defined on this advanced query
+		patientName = request.getParameter("patientName");
+		patientID = request.getParameter("patientID");
+		patientGender = request.getParameter("patientGender");
+		institutionName = request.getParameter("institutionName");
+		physician = request.getParameter("physician");
+		operatorName = request.getParameter("operatorName");
+		studyDateFormat = request.getParameter("studyDate");
+		exactDate = request.getParameter("exactDate");
+		useStartDate = Utils.parseCheckBoxValue(request
+				.getParameter("fromDate"));
+		useEndDate = Utils.parseCheckBoxValue(request.getParameter("toDate"));
+		startDate = request.getParameter("startDate");
+		endDate = request.getParameter("endDate");
+		modCR = Utils.parseCheckBoxValue(request.getParameter("modCR"));
+		modMG = Utils.parseCheckBoxValue(request.getParameter("modMG"));
+		modPT = Utils.parseCheckBoxValue(request.getParameter("modPT"));
+		modXA = Utils.parseCheckBoxValue(request.getParameter("modXA"));
+		modES = Utils.parseCheckBoxValue(request.getParameter("modES"));
+		modCT = Utils.parseCheckBoxValue(request.getParameter("modCT"));
+		modMR = Utils.parseCheckBoxValue(request.getParameter("modMR"));
+		modRF = Utils.parseCheckBoxValue(request.getParameter("modRF"));
+		modUS = Utils.parseCheckBoxValue(request.getParameter("modUS"));
+		modDX = Utils.parseCheckBoxValue(request.getParameter("modDX"));
+		modNM = Utils.parseCheckBoxValue(request.getParameter("modNM"));
+		modSC = Utils.parseCheckBoxValue(request.getParameter("modSC"));
+		modOT = Utils.parseCheckBoxValue(request.getParameter("modOT"));
+		modOthers = Utils.parseCheckBoxValue(request.getParameter("modOthers"));
+
+		// and form the query string
+		finalQuery = getAdvancedQuery();
+	}
+
+	/**
+	 * Returns a String with a valid query, that can be combined with others if
+	 * needed, for searching for all modalities currently defined on the web
+	 * interface (supported directly, minus the Others).
+	 * 
+	 * @return a String with a valid query, that can be combined with others if
+	 *         needed, for searching for all modalities currently defined on the
+	 *         web interface (supported directly, minus the Others).
+	 */
+	private List<String> getAllDefinedModalitiesQuery() {
+		List<String> ret = new ArrayList<>(13);
+
+                                ret.add("CR");
+                                ret.add("CT");
+                                ret.add("DX");
+                                ret.add("ES");
+                                ret.add("MG");
+                                ret.add("MR");
+                                ret.add("NM");
+                                ret.add("OT");
+                                ret.add("PT");
+                                ret.add("RF");
+                                ret.add("SC");
+                                ret.add("US");
+                                ret.add("XA");             
+
+		return ret;
+	}
+
+	/**
+	 * Based on the set of optional advanced search params, returns a advanced
+	 * query string that reflects those params.
+	 * 
+	 * @return an advanced query string for the params that match their values.
+	 */
+	public String getAdvancedQuery() {
+		String result = "";
+
+		// patient name
+		if ((patientName != null) && (!patientName.isEmpty())) {
+			result = addExtraQueryParam(result, "PatientName:(" + patientName
+					+ ")");
+		}
+
+		// patient id
+		if ((patientID != null) && (!patientID.isEmpty())) {
+			result = addExtraQueryParam(result, "PatientID:(" + patientID + ")");
+		}
+
+		// patient gender
+		if ((patientGender != null) && (!patientGender.isEmpty())
+				&& (!isPatientGenderAll())) {
+			if (isPatientGenderMale()) {
+				result = addExtraQueryParam(result, "PatientSex:M");
+			} else {
+				if (isPatientGenderFemale()) {
+					result = addExtraQueryParam(result, "PatientSex:F");
+				}
+			}
+		}
+
+		// institution name
+		if ((institutionName != null) && (!institutionName.isEmpty())) {
+			result = addExtraQueryParam(result, "InstitutionName:("
+					+ institutionName + ")");
+		}
+
+		// physician
+		if ((physician != null) && (!physician.isEmpty())) {
+			result = addExtraQueryParam(result, "(PerformingPhysicianName:("
+					+ physician + ") OR ReferringPhysicianName:(" + physician
+					+ "))");
+		}
+
+		// operator name
+		if ((operatorName != null) && (!operatorName.isEmpty())) {
+			result = addExtraQueryParam(result, "OperatorName:(" + operatorName
+					+ ")");
+		}
+
+		// study date
+		if ((studyDateFormat != null) && (!studyDateFormat.isEmpty())) {
+			if (studyDateFormat.equalsIgnoreCase("Exact")) {
+				if ((exactDate != null) && (!exactDate.isEmpty()))
+					result = addExtraQueryParam(result, "StudyDate:("
+							+ exactDate + ")");
+			} else {
+				if (studyDateFormat.equalsIgnoreCase("Range")) {
+					String date = "StudyDate:[";
+
+					if (useStartDate && (startDate != null)
+							&& (!startDate.isEmpty())) {
+						date += startDate;
+					} else {
+						date += "0000101";
+					}
+					date += " TO ";
+					if (useEndDate && (endDate != null) && (!endDate.isEmpty())) {
+						date += endDate;
+					} else {
+						Calendar cal = Calendar.getInstance();
+						SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+
+						date += sdf.format(cal.getTime());
+					}
+
+					date += "]";
+
+					result = addExtraQueryParam(result, date);
+				}
+			}
+		}
+
+		// modalities
+		{
+			String modalities = "";
+                                                Set<String> mods = new HashSet<String>();
+                        
+                        
+                                                 if (modCR) {
+                                                                mods.add("CR");
+                                                    }
+                                                        if (modCT) {
+                                                                mods.add("CT");
+                                                        }
+                                                        if (modDX) {
+                                                                mods.add("DX");
+                                                        }
+                                                        if (modES) {
+                                                                mods.add("ES");
+                                                        }
+                                                        if (modMG) {
+                                                                mods.add("MG");
+                                                        }
+                                                        if (modMR) {
+                                                                mods.add("MR");
+                                                        }
+                                                        if (modNM) {
+                                                                mods.add("NM");
+                                                        }
+                                                        if (modOT) {
+                                                                mods.add("OT");
+                                                        }
+                                                        if (modPT) {
+                                                                mods.add("PT");
+                                                        }
+                                                        if (modRF) {
+                                                                mods.add("RF");
+                                                        }
+                                                        if (modSC) {
+                                                                mods.add("SC");
+                                                        }
+                                                        if (modUS) {
+                                                                mods.add("US");
+                                                        }
+                                                        if (modXA) {
+                                                                mods.add("XA");
+                                                        }
+                                                                                
+                                                        for(String s : mods){
+                                                            modalities+=s +" ";
+                                                        }
+                                                        
+                                                        if(modOthers){
+                                                            for(String s : getAllDefinedModalitiesQuery()){
+                                                                if(!mods.contains(s))
+                                                                    modalities += "-"+s+" ";
+                                                            }
+                                                        }                                                       
+                                                
+			// and add the modalities to the resulting query
+			if (!modalities.isEmpty()) {
+				result = addExtraQueryParam(result, "Modality:(" + modalities + ")");
+			}
+		}
+
+		// if no "options" were modified then use the default query string
+		if (result.isEmpty()) {
+			result = "*:*";
+		}
+
+		return result;
+	}
+
+	/**
+	 * Returns if there is a query to be used (NOTE: an empty string is still a
+	 * valid query!).
+	 * 
+	 * @return if there is a query to be used.
+	 */
+	public boolean hasQuery() {
+		return ((!isAdvanced) && (simpleQuery != null)) || isAdvanced;
+	}
+
+	/**
+	 * Returns the original query.
+	 * 
+	 * @return the original query.
+	 */
+	public String getSimpleQuery() {
+		return simpleQuery;
+	}
+
+	/**
+	 * Returns the final query.
+	 * 
+	 * @return the final query.
+	 */
+	public String getFinalQuery() {
+		return finalQuery;
+	}
+
+	/**
+	 * Returns a list with the search results for the query.
+	 * 
+	 * @return a list with the search results for the query.
+	 */
+	@Deprecated
+	public Collection<SearchResult> getSearchResults() {
+		// if there is no valid query then abort
+		if (!hasQuery())
+			return null;
+
+		// if the value is not cached then do the search and cache it
+		if (searchResults == null) {
+			// perform the search
+			long startime = System.nanoTime();
+			searchResults = search(finalQuery, fullRequest);
+			long endTime = System.nanoTime();
+			// update the time taken for the search to complete
+			timeTaken = (endTime - startime) / 1000000;
+		}
+
+		return searchResults;
+	}
+
+	/**
+	 * Returns the Selected Query Providers in the JSON Format
+	 * @return The selected Query Providers
+	 */
+	public String getQueryProvidersJSON() {
+
+		JSONArray arr = new JSONArray();
+
+		for (String p : getQueryProviders()) {
+			JSONObject obj = new JSONObject();
+			obj.put("name", p);
+			boolean sel = this.selectedProviders.contains(p);
+			obj.put("selected", sel);
+			arr.add(obj);
+		}
+
+		return arr.toString();
+	}
+
+	/**
+	 * Returns a List containing the Selected Query Providers
+	 * @return The selected Query Providers 
+	 */
+	public List<String> getQueryProviders() {
+		List<String> providers = PluginController.getInstance()
+				.getQueryProvidersName(true);
+
+		return providers;
+	}
+
+	/**
+	 * @return
+	 */
+	public List<String> getSelectedProviders() {
+		return this.selectedProviders;
+	}
+
+	/**
+	 * Places a new search in the SearchHolder
+	 * @param query The query String
+	 * @return The Given Query Identifier
+	 */
+	private int fireSearch(String query) {
+		if (selectedProviders.isEmpty())
+			return -1;
+
+		HashMap<String, String> searchParam = new HashMap<>();
+
+		searchParam.put("PatientName", "PatientName");
+		searchParam.put("Modality", "Modality");
+		searchParam.put("StudyDate", "StudyDate");
+		searchParam.put("SOPInstanceUID", "SOPInstanceUID");
+		searchParam.put("Thumbnail", "Thumbnail");
+		searchParam.put("StudyDescription", "StudyDescription");
+		searchParam.put("InstitutionName", "InstitutionName");
+		searchParam.put("SeriesDescription", "SeriesDescription");
+		searchParam.put("PatientID", "PatientID");
+		searchParam.put("PatientSex", "PatientSex");
+
+		if (httpSession == null)
+			return -1;
+
+		SearchHolder holder = (SearchHolder) httpSession
+				.getAttribute("dicoogle.web.queryHolder");
+		if (holder == null) {
+			holder = new SearchHolder();
+			httpSession.setAttribute("dicoogle.web.queryHolder", holder);
+		}
+
+		int id = holder.registerNewQuery(selectedProviders, query, searchParam);
+
+		return id;
+	}
+
+	/**
+	 * Places the search in the Holder. If it has not been done before.
+	 * @return
+	 */
+	public int placeSearchOrder() {
+		// if there is no valid query then abort
+		if (!hasQuery())
+			return -1;
+
+			
+		// performs the search, if it hasn't already
+		if(searchID == -1)
+			searchID = fireSearch(finalQuery);
+
+		return searchID;
+	}
+
+	/**
+	 * Performs a simple search.
+	 * 
+	 * @param query
+	 *            the user entered query.
+	 * @return a list of SearchResult objects.
+	 */
+	@Deprecated
+	private Collection<SearchResult> search(String query, boolean fullRequest) {
+		if (selectedProviders.isEmpty())
+			return Collections.emptyList();
+		// get the search results for this query
+		// results = idx.searchSync(query, (fullRequest ? extraFieldsFull :
+		// extraFields));
+
+		List<SearchResult> targetCollection = new ArrayList<SearchResult>();
+		Iterable<SearchResult> itResults = null;
+
+		HashMap<String, String> searchParam = new HashMap<>();
+
+		searchParam.put("PatientName", "PatientName");
+		searchParam.put("Modality", "Modality");
+		searchParam.put("StudyDate", "StudyDate");
+		searchParam.put("SOPInstanceUID", "SOPInstanceUID");
+		searchParam.put("Thumbnail", "Thumbnail");
+		searchParam.put("StudyDescription", "StudyDescription");
+		searchParam.put("InstitutionName", "InstitutionName");
+		searchParam.put("SeriesDescription", "SeriesDescription");
+		searchParam.put("PatientID", "PatientID");
+		searchParam.put("PatientSex", "PatientSex");
+		try {
+			// for(String provider : selectedProviders){
+			// System.out.println("Searching in Provider: "+provider);
+			JointQueryTask t = new JointQueryTask() {
+
+				@Override
+				public void onReceive(Task<Iterable<SearchResult>> e) {
+					// TODO Auto-generated method stub
+
+				}
+
+				@Override
+				public void onCompletion() {
+					// TODO Auto-generated method stub
+
+				}
+			};
+			itResults = PluginController.getInstance()
+					.query(t, selectedProviders, query, searchParam).get();
+
+			// }
+
+		} catch (InterruptedException | ExecutionException ex) {
+			LoggerFactory.getLogger(Search.class).error(ex.getMessage(), ex);
+		}
+
+		if (itResults == null)
+			return Collections.emptyList();
+
+		for (SearchResult s : itResults) {
+			targetCollection.add(s);
+		}
+
+		// and return them
+		return targetCollection;
+	}
+
+	/**
+	 * @return the isAdvanced
+	 */
+	public boolean isAdvancedQuery() {
+		return isAdvanced;
+	}
+
+	/**
+	 * @return the patientName
+	 */
+	public String getPatientName() {
+		return patientName;
+	}
+
+	/**
+	 * @return the patientID
+	 */
+	public String getPatientID() {
+		return patientID;
+	}
+
+	/**
+	 * @return the patientGender
+	 */
+	public String getPatientGender() {
+		return patientGender;
+	}
+
+	public boolean isPatientGenderAll() {
+		return (patientGender == null)
+				|| patientGender.isEmpty()
+				|| patientGender.equalsIgnoreCase("All")
+				|| ((!patientGender.equalsIgnoreCase("Male")) && (!patientGender
+						.equalsIgnoreCase("Female")));
+	}
+
+	public boolean isPatientGenderMale() {
+		return (patientGender != null)
+				&& patientGender.equalsIgnoreCase("Male");
+	}
+
+	public boolean isPatientGenderFemale() {
+		return (patientGender != null)
+				&& patientGender.equalsIgnoreCase("Female");
+	}
+
+	/**
+	 * @return the institutionName
+	 */
+	public String getInstitutionName() {
+		return institutionName;
+	}
+
+	/**
+	 * @return the physician
+	 */
+	public String getPhysician() {
+		return physician;
+	}
+
+	/**
+	 * @return the operatorName
+	 */
+	public String getOperatorName() {
+		return operatorName;
+	}
+
+	/**
+	 * @return the studyDateFormat
+	 */
+	public String getStudyDateFormat() {
+		return studyDateFormat;
+	}
+
+	public boolean isExactDate() {
+		return (studyDateFormat != null) && (!studyDateFormat.isEmpty())
+				&& studyDateFormat.equalsIgnoreCase("Exact");
+	}
+
+	public boolean isRangedDate() {
+		return (studyDateFormat != null) && (!studyDateFormat.isEmpty())
+				&& studyDateFormat.equalsIgnoreCase("Range");
+	}
+
+	/**
+	 * @return the exactDate
+	 */
+	public String getExactDate() {
+		return exactDate;
+	}
+
+	/**
+	 * @return the useStartDate
+	 */
+	public boolean isUseStartDate() {
+		return useStartDate;
+	}
+
+	/**
+	 * @return the useEndDate
+	 */
+	public boolean isUseEndDate() {
+		return useEndDate;
+	}
+
+	/**
+	 * @return the startDate
+	 */
+	public String getStartDate() {
+		return startDate;
+	}
+
+	/**
+	 * @return the endDate
+	 */
+	public String getEndDate() {
+		return endDate;
+	}
+
+	/**
+	 * @return the modCR
+	 */
+	public boolean isModCR() {
+		return modCR;
+	}
+
+	/**
+	 * @return the modMG
+	 */
+	public boolean isModMG() {
+		return modMG;
+	}
+
+	/**
+	 * @return the modPT
+	 */
+	public boolean isModPT() {
+		return modPT;
+	}
+
+	/**
+	 * @return the modXA
+	 */
+	public boolean isModXA() {
+		return modXA;
+	}
+
+	/**
+	 * @return the modES
+	 */
+	public boolean isModES() {
+		return modES;
+	}
+
+	/**
+	 * @return the modCT
+	 */
+	public boolean isModCT() {
+		return modCT;
+	}
+
+	/**
+	 * @return the modMR
+	 */
+	public boolean isModMR() {
+		return modMR;
+	}
+
+	/**
+	 * @return the modRF
+	 */
+	public boolean isModRF() {
+		return modRF;
+	}
+
+	/**
+	 * @return the modUS
+	 */
+	public boolean isModUS() {
+		return modUS;
+	}
+
+	/**
+	 * @return the modDX
+	 */
+	public boolean isModDX() {
+		return modDX;
+	}
+
+	/**
+	 * @return the modNM
+	 */
+	public boolean isModNM() {
+		return modNM;
+	}
+
+	/**
+	 * @return the modSC
+	 */
+	public boolean isModSC() {
+		return modSC;
+	}
+
+	/**
+	 * @return the modOT
+	 */
+	public boolean isModOT() {
+		return modOT;
+	}
+
+	/**
+	 * @return the modOthers
+	 */
+	public boolean isModOthers() {
+		return modOthers;
+	}
+
+	/**
+	 * @return the keyworded
+	 */
+	public boolean isKeyworded() {
+		return keyworded;
+	}
+
+	/**
+	 * @return the time taken for the search to complete in milliseconds.
+	 */
+	public long getTimeTaken() {
+		return timeTaken;
+	}
+	
+	public static String getAllTags(){
+		List<String> tags = new ArrayList<String>( DictionaryAccess.getInstance().getTagList().keySet() );
+		Collections.sort(tags);
+		JSONArray arr = JSONArray.fromObject(tags);
+		return arr.toString();		
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchHolder.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchHolder.java
new file mode 100644
index 0000000..7fbf452
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchHolder.java
@@ -0,0 +1,181 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.dicom;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.commons.collections.Buffer;
+import org.apache.commons.collections.BufferUtils;
+import org.apache.commons.collections.KeyValue;
+import org.apache.commons.collections.buffer.UnboundedFifoBuffer;
+import org.apache.commons.collections.keyvalue.DefaultKeyValue;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+public class SearchHolder {
+
+	@SuppressWarnings("unused") //TODO: IMPLEMENT THIS
+	private static int maxNumberOfTasks = 3;
+	private Map<Integer, QueryHandler> tasks;
+	
+	public SearchHolder() {
+		tasks = new HashMap<Integer, SearchHolder.QueryHandler>();
+	}
+
+	public synchronized int registerNewQuery(List<String> providers, String query, Object searchParam){
+		QueryHandler task = new QueryHandler();
+		
+		task = (QueryHandler) PluginController.getInstance().query(task, providers, query, searchParam);
+		if(task == null)
+			return -1;
+		
+		tasks.put(task.hashCode(), task);
+		return task.hashCode();
+	}
+	
+	public synchronized void removeQuery(int id){
+		tasks.remove(id);
+	}
+	
+	public  synchronized Iterable<KeyValue> retrieveQueryOutput(int id){
+		QueryHandler task = tasks.get(id);
+	
+		if(task == null)
+			return null;
+		
+		return task;
+	}
+	
+	private class QueryHandler extends JointQueryTask implements Iterable<KeyValue>{
+
+		private StringBuffer buffer;	
+		private List<KeyValue> tempResults;
+		private List<InnerIterator> currentIterators;
+		
+		public QueryHandler() {
+			super();
+			buffer = new StringBuffer();
+			currentIterators = new ArrayList<InnerIterator>();
+			tempResults = new ArrayList<>();
+		}
+
+		@Override
+		public void onCompletion() {
+			// TODO Auto-generated method stub
+			System.out.println("Completed Query");
+		}
+
+		@Override
+		public void onReceive(Task<Iterable<SearchResult>> e) {
+			// TODO Auto-generated method stub
+			try {
+				System.out.println("RECEIVED NEW ITERATION: ");
+				
+				Iterable<SearchResult> results = e.get();
+				DefaultKeyValue keyValue = new DefaultKeyValue(e.getName(), results);
+				
+				appendResult(keyValue);
+				
+				/*for(SearchResult res : results ){
+					
+				}*/	
+			} catch (InterruptedException | ExecutionException e1) {
+				// TODO Auto-generated catch block
+				//e1.printStackTrace();
+			}
+			
+			buffer.append("Received Query: "+e.getName());
+		}
+
+		@SuppressWarnings("unchecked")
+		private synchronized void appendResult(DefaultKeyValue keyValue) {
+			tempResults.add(keyValue);
+			
+			for(InnerIterator it : currentIterators){
+				it.resultBuffer.add(keyValue);				
+			}
+		}
+		
+		private synchronized InnerIterator createIterator(){
+			InnerIterator it = new InnerIterator(tempResults);
+			currentIterators.add(it);
+			
+			return it; 
+		}
+
+		@Override
+		public Iterator<KeyValue> iterator() {
+			if(isDone() || isCancelled())
+				return tempResults.iterator();
+			
+			return createIterator();
+		}
+		
+		private class InnerIterator implements Iterator<KeyValue>{
+
+			private Buffer resultBuffer;
+			
+			@SuppressWarnings("unchecked")
+			public InnerIterator(List<KeyValue> tempResults) {
+				int size = tempResults.size();
+				if(size <= 0)
+					size = 1;
+				resultBuffer = BufferUtils.blockingBuffer( new UnboundedFifoBuffer(size) );
+				resultBuffer.addAll(tempResults);
+			}
+
+			@Override
+			public boolean hasNext() {
+				if(!(isCancelled() || isDone()))
+					return true;
+				
+				return !resultBuffer.isEmpty();
+			}
+
+			@Override
+			public KeyValue next() {
+				return (KeyValue) resultBuffer.remove();
+			}
+
+			@Override
+			public void remove() {				
+			}
+			
+		}
+		
+	}
+
+	public boolean isDone(int id) {
+		QueryHandler task = tasks.get(id);
+		
+		if(task == null)
+			return true;
+		
+		return task.isDone() || task.isCancelled();
+	}
+		
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchResultsTree.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchResultsTree.java
new file mode 100644
index 0000000..f417ed0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/dicom/SearchResultsTree.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.dicom;
+
+/**
+ *
+ * @author Antonio
+ */
+public class SearchResultsTree
+{
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Dicoogle.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Dicoogle.java
new file mode 100644
index 0000000..d41da8d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Dicoogle.java
@@ -0,0 +1,844 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.management;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.dcm4che2.data.UID;
+import pt.ua.dicoogle.server.SOPList;
+import pt.ua.dicoogle.server.TransfersStorage;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.sdk.settings.InvalidSettingValueException;
+import pt.ua.dicoogle.sdk.settings.types.CheckboxWithHint;
+import pt.ua.dicoogle.sdk.settings.types.ComboBox;
+import pt.ua.dicoogle.sdk.settings.types.RangeInteger;
+import pt.ua.dicoogle.sdk.settings.types.ServerDirectoryPath;
+import pt.ua.dicoogle.sdk.settings.types.DataTable;
+import pt.ua.dicoogle.sdk.settings.types.StaticDataTable;
+import static pt.ua.dicoogle.sdk.settings.Utils.parseCheckBoxValue;
+
+/**
+ * A wrapper used to manage the Dicoogle Settings remotely through the web environment/app.
+ */
+public class Dicoogle
+{
+	/**
+	 * The current instance of this class.
+	 */
+	private static Dicoogle instance;
+
+	/**
+	 * Pointer to a object that maintain the ServerSettings configuration.
+	 */
+	private static ServerSettings cfg;
+
+	/**
+	 * Indexing.
+	 */
+
+	/**
+	 * The name of the setting that indicates the Dicoogle Directory Monitorization.
+	 */
+	public static final String SETTING_DIRECTORY_MONITORIZATION_NAME = "Dicoogle Directory Monitorization";
+	/**
+	 * The name of the setting that indicates the Dicoogle Enable Directory Watcher.
+	 */
+	public static final String SETTING_DIRECTORY_WATCHER_NAME = "Enable Dicoogle Directory Watcher";
+	/**
+	 * The name of the setting that indicates the Indexing Effort.
+	 */
+	public static final String SETTING_INDEXING_EFFORT_NAME = "Indexing Effort";
+	/**
+	 * The name of the setting that indicates the Thumbnails Size.
+	 */
+	public static final String SETTING_THUMBNAILS_SIZE_NAME = "Thumbnails Size";
+	/**
+	 * The name of the setting that indicates if Thumbnails are to be Saved.
+	 */
+	public static final String SETTING_SAVE_THUMBNAILS_NAME = "Save Thumbnails";
+	/**
+	 * The name of the setting that indicates if ZIP files are to be Indexed.
+	 */
+	public static final String SETTING_INDEX_ZIP_FILES_NAME = "Index ZIP Files";
+
+	/**
+	 * Access List.
+	 */
+
+	/**
+	 * The name of the setting that indicates the Server AE Title.
+	 */
+	public static final String SETTING_SERVER_AE_TITLE_NAME = "Server AE Title";
+	/**
+	 * The name of the setting that indicates the Permit All AE Titles.
+	 */
+	public static final String SETTING_PERMIT_ALL_AE_TITLES_NAME = "Permit All AE Titles";
+	/**
+	 * The name of the setting that indicates the Client Permit Access List.
+	 */
+	public static final String SETTING_CLIENT_PERMIT_ACCESS_LIST_NAME = "Client Permit Access List";
+
+	/**
+	 * SOP Class/Transfer Storage.
+	 */
+
+	/**
+	 * The name of the setting that indicates if Accept All SOP Classes.
+	 */
+	public static final String SETTING_SOP_CLASS_ACCEPT_ALL_NAME = "Accept All";
+	/**
+	 * The name of the setting that indicates the Global Transfer Storage settings.
+	 */
+	public static final String SETTING_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_NAME = "Global Transfer Storage";
+
+	/**
+	 * Indexing Help.
+	 */
+
+	/**
+	 * The help of the Indexing Effort setting.
+	 */
+	public static final String SETTING_INDEXING_EFFORT_HELP = "How agressive should the indexing effort be.\n\n0 - Lower\n100 - Intensive";
+
+	/**
+	 * Access List Help.
+	 */
+
+	/**
+	 * The help for the setting that indicates the Server AE Title.
+	 */
+	public static final String SETTING_SERVER_AE_TITLE_HELP = "Setting an AE Title will force the server to only accept connections adressed to the given AE Title.";
+	/**
+	 * The help of the setting that indicates the Permit All AE Titles.
+	 */
+	public static final String SETTING_PERMIT_ALL_AE_TITLES_HELP = "Overrides the Client Permit Access List settings, making the server accept connection from clients with any AE Title.";
+	/**
+	 * The help for the setting that indicates the Client Permit Access List.
+	 */
+	public static final String SETTING_CLIENT_PERMIT_ACCESS_LIST_HELP = "Adding an AE Title to the Access Control List will force the server to only accept connections from clients with those AE Titles.";
+
+	private Dicoogle()
+	{
+		cfg = ServerSettings.getInstance();
+	}
+
+	/**
+	 * Returns the current instance of this class.
+	 *
+	 * @return the current instance of this class.
+	 */
+	public synchronized static Dicoogle getInstance()
+	{
+		if (instance == null)
+			instance = new Dicoogle();
+
+		return instance;
+	}
+
+	/**
+	 * Indexing.
+	 */
+
+	/**
+	 * Returns a Map containing the current settings.
+	 *
+	 * @return a Map containing the current settings.
+	 */
+	public HashMap<String, Object> getIndexingSettings()
+	{
+		HashMap<String, Object> settings = new LinkedHashMap<String, Object>();
+
+		settings.put(SETTING_DIRECTORY_WATCHER_NAME, new Boolean(cfg.isMonitorWatcher()));
+		settings.put(SETTING_DIRECTORY_MONITORIZATION_NAME, new ServerDirectoryPath(cfg.getDicoogleDir()));
+		settings.put(SETTING_INDEX_ZIP_FILES_NAME, cfg.isIndexZIPFiles());
+		settings.put(SETTING_INDEXING_EFFORT_NAME, new RangeInteger(0, 100, cfg.getIndexerEffort()));
+		settings.put(SETTING_SAVE_THUMBNAILS_NAME, cfg.getSaveThumbnails());
+		settings.put(SETTING_THUMBNAILS_SIZE_NAME, cfg.getThumbnailsMatrix()); // TODO add more descritive type
+
+		return settings;
+	}
+
+	/**
+	 * Returns the settings help.
+	 *
+	 * @return a HashMap containing the setting help.
+	 */
+	public HashMap<String, String> getIndexingSettingsHelp()
+	{
+		HashMap<String, String> settings = new HashMap<String, String>();
+
+		// right now this is the only settingg that needs some help describing it
+		settings.put(SETTING_INDEXING_EFFORT_NAME, SETTING_INDEXING_EFFORT_HELP);
+
+		return settings;
+	}
+
+	/**
+	 * Validates the settings supplied and checks if they are valid ones.
+	 *
+	 * @param map a Map containing the settings.
+	 * @return true if all the settings are valid.
+	 * @throws InvalidSettingValueException if at least one of the settings is invalid.
+	 */
+	public boolean tryIndexingSettings(HashMap<String, Object> map) throws InvalidSettingValueException
+	{
+		// TODO remmember to check for null, all the params are supplied, all have valid types, and oly then all have valid values
+
+		return true;
+	}
+
+	/**
+	 * Tries to set the supplied settings as the new settings.
+	 *
+	 * @param settings a Map containing the new settings.
+	 * @return true if all settings were successfully changed to the ones supplied, false otherwise (no settings changed).
+	 */
+	public boolean setIndexingSettings(HashMap<String, Object> settings)
+	{
+		// validate the settings
+		boolean valid = false;
+		try
+		{
+			valid = tryIndexingSettings(settings);
+		}
+		catch (InvalidSettingValueException ex)
+		{
+			// at least one of the setting is invalid, abort
+			return false;
+		}
+		if (! valid) //settings not valid due to unknown reason, also abort
+			return false;
+
+		// all the settings were correctly validated, so apply them all
+		cfg.setDicoogleDir(((ServerDirectoryPath) settings.get(SETTING_DIRECTORY_MONITORIZATION_NAME)).getPath());
+		cfg.setMonitorWatcher(((Boolean) settings.get(SETTING_DIRECTORY_WATCHER_NAME)).booleanValue());
+		cfg.setIndexerEffort(((RangeInteger) settings.get(SETTING_INDEXING_EFFORT_NAME)).getValue());
+		cfg.setThumbnailsMatrix((String) settings.get(SETTING_THUMBNAILS_SIZE_NAME));
+		cfg.setSaveThumbnails(((Boolean) settings.get(SETTING_SAVE_THUMBNAILS_NAME)).booleanValue());
+		cfg.setIndexZIPFiles(((Boolean) settings.get(SETTING_INDEX_ZIP_FILES_NAME)).booleanValue());
+
+		// return success
+		return true;
+	}
+
+	/**
+	 * Access List.
+	 */
+
+	/**
+	 * Returns a Map containing the current settings.
+	 *
+	 * @return a Map containing the current settings.
+	 */
+	public HashMap<String, Object> getAccessListSettings()
+	{
+		HashMap<String, Object> settings = new LinkedHashMap<String, Object>();
+
+		settings.put(SETTING_SERVER_AE_TITLE_NAME, cfg.getAE());
+		settings.put(SETTING_PERMIT_ALL_AE_TITLES_NAME, new Boolean(cfg.getPermitAllAETitles()));
+		String[] caet = cfg.getCAET();
+		DataTable clientPermitACL = new DataTable(1, caet.length);
+		clientPermitACL.setColumnName(0, "Client AE Title");
+		if (caet.length < 1)
+		{
+			clientPermitACL.addRow();
+			clientPermitACL.setCellData(0, 0, "");
+		}
+		else
+		{
+			for (int i = 0; i < caet.length; i++)
+				clientPermitACL.setCellData(i, 0, caet[i]);
+		}
+		settings.put(SETTING_CLIENT_PERMIT_ACCESS_LIST_NAME, clientPermitACL);
+
+		return settings;
+	}
+
+	/**
+	 * Returns the settings help.
+	 *
+	 * @return a HashMap containing the setting help.
+	 */
+	public HashMap<String, String> getAccessListSettingsHelp()
+	{
+		HashMap<String, String> settings = new HashMap<String, String>();
+
+		settings.put(SETTING_SERVER_AE_TITLE_NAME, SETTING_SERVER_AE_TITLE_HELP);
+		settings.put(SETTING_PERMIT_ALL_AE_TITLES_NAME, SETTING_PERMIT_ALL_AE_TITLES_HELP);
+		settings.put(SETTING_CLIENT_PERMIT_ACCESS_LIST_NAME, SETTING_CLIENT_PERMIT_ACCESS_LIST_HELP);
+
+		return settings;
+	}
+
+	/**
+	 * Validates the settings supplied and checks if they are valid ones.
+	 *
+	 * @param map a Map containing the settings.
+	 * @return true if all the settings are valid.
+	 * @throws InvalidSettingValueException if at least one of the settings is invalid.
+	 */
+	public boolean tryAccessListSettings(HashMap<String, Object> map) throws InvalidSettingValueException
+	{
+		// TODO remmember to check for null, all the params are supplied, all have valid types, and oly then all have valid values
+
+		return true;
+	}
+
+	/**
+	 * Tries to set the supplied settings as the new settings.
+	 *
+	 * @param settings a Map containing the new settings.
+	 * @return true if all settings were successfully changed to the ones supplied, false otherwise (no settings changed).
+	 */
+	public boolean setAccessListSettings(HashMap<String, Object> settings)
+	{
+		// validate the settings
+		boolean valid = false;
+		try
+		{
+			valid = tryAccessListSettings(settings);
+		}
+		catch (InvalidSettingValueException ex)
+		{
+			// at least one of the setting is invalid, abort
+			return false;
+		}
+		if (! valid) //settings not valid due to unknown reason, also abort
+			return false;
+
+		// all the settings were correctly validated, so apply them all
+		cfg.setAE((String) settings.get(SETTING_SERVER_AE_TITLE_NAME));
+		cfg.setPermitAllAETitles(((Boolean) settings.get(SETTING_PERMIT_ALL_AE_TITLES_NAME)).booleanValue());
+		DataTable clientPermitACL = (DataTable) settings.get(SETTING_CLIENT_PERMIT_ACCESS_LIST_NAME);
+		LinkedList<String> caet = new LinkedList<String>();
+		if ((clientPermitACL.getRowCount() != 1) || (clientPermitACL.getCellData(0, 0) != ""))
+			for (int i = 0; i < clientPermitACL.getRowCount(); i++)
+				caet.add((String) clientPermitACL.getCellData(i, 0));
+		cfg.setCAET(caet.toArray(new String[caet.size()]));
+
+		// return success
+		return true;
+	}
+
+	/**
+	 * SOP Classes / Transfer Storage.
+	 */
+
+	/**
+	 * Returns a Map containing the current settings.
+	 *
+	 * @return a Map containing the current settings.
+	 */
+	public HashMap<String, Object> getSOPClassGlobalSettings()
+	{
+		HashMap<String, Object> settings = new LinkedHashMap<String, Object>();
+
+		Object[] set = getTransferSettingsForAllSOPClasses();
+
+		ComboBox tristate = new ComboBox();
+		tristate.addElement("As Is (No Change)", "");
+		tristate.addElement("Allow All", "On"); // try to emulate a regular checkbox :)
+		tristate.addElement("Forbid All", "Off");
+		tristate.setCurrentByValue(""); // FIXME default is "no change", always (for the time being)
+		settings.put(SETTING_SOP_CLASS_ACCEPT_ALL_NAME, tristate);
+		settings.put(SETTING_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_NAME, set[1]);
+
+		return settings;
+	}
+
+	/**
+	 * Returns the settings help.
+	 *
+	 * @return a HashMap containing the setting help.
+	 */
+	public HashMap<String, String> getSOPClassGlobalSettingsHelp()
+	{
+		HashMap<String, String> settings = new HashMap<String, String>();
+
+		// TODO
+
+		return settings;
+	}
+
+	/**
+	 * Validates the settings supplied and checks if they are valid ones.
+	 *
+	 * @param map a Map containing the settings.
+	 * @return true if all the settings are valid.
+	 * @throws InvalidSettingValueException if at least one of the settings is invalid.
+	 */
+	public boolean trySOPClassGlobalSettings(HashMap<String, Object> map) throws InvalidSettingValueException
+	{
+		// TODO remmember to check for null, all the params are supplied, all have valid types, and oly then all have valid values
+
+		return true;
+	}
+
+	/**
+	 * Tries to set the supplied settings as the new settings.
+	 *
+	 * @param settings a Map containing the new settings.
+	 * @return true if all settings were successfully changed to the ones supplied, false otherwise (no settings changed).
+	 */
+	public boolean setSOPClassGlobalSettings(HashMap<String, Object> settings)
+	{
+		// validate the settings
+		boolean valid = false;
+		try
+		{
+			valid = tryAccessListSettings(settings);
+		}
+		catch (InvalidSettingValueException ex)
+		{
+			// at least one of the setting is invalid, abort
+			return false;
+		}
+		if (! valid) //settings not valid due to unknown reason, also abort
+			return false;
+
+		// all the settings were correctly validated, so apply them all
+		ComboBox tristate = (ComboBox) settings.get(SETTING_SOP_CLASS_ACCEPT_ALL_NAME);
+		Boolean accepted = null;
+		if (! tristate.getCurrentValue().isEmpty()) // NOTE: empty ("") means no change, see the getter for this settings
+			accepted = new Boolean(parseCheckBoxValue(tristate.getCurrentValue()));
+		StaticDataTable table = (StaticDataTable) settings.get(SETTING_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_NAME);
+
+		setTransferSettingsForAllSOPClasses(accepted, table);
+
+		// return success
+		return true;
+	}
+
+	/**
+	 * Holds and provides information about the accepted SOP Classes and
+	 * Transfer Storages allowed within Dicoogle.
+	 */
+	public static class SOPClassSettings
+	{
+		/**
+		 * Holds a pointer to the SOPList that holds the SOP Classes settings.
+		 */
+		private SOPList sopList;
+
+		/**
+		 * Holds the list of SOP Classes UIDs and their respective "regular" name.
+		 */
+		private HashMap<String, String> sopClasses;
+		/**
+		 * Holds the list of Transfer Storage UIDs and their respective "regular" name.
+		 */
+		private HashMap<String, String> transferSettings;
+		/**
+		 * Holds the list of Transfer Storage UIDs and their respective index on the TS object.
+		 */
+		private HashMap<String, Integer> transferSettingsIndex;
+
+		/**
+		 * Holds the current instance of this class.
+		 */
+		private static SOPClassSettings instance;
+
+		private SOPClassSettings()
+		{
+			sopList = SOPList.getInstance();
+
+			sopClasses = new HashMap<String, String>();
+			transferSettings = new HashMap<String, String>();
+			transferSettingsIndex = new HashMap<String, Integer>();
+
+			sopClasses.put(UID.BasicStudyContentNotificationSOPClassRetired, "BasicStudyContentNotification (Retired)");
+			sopClasses.put(UID.StoredPrintStorageSOPClassRetired, "StoredPrintStorage (Retired)");
+			sopClasses.put(UID.HardcopyGrayscaleImageStorageSOPClassRetired, "HardcopyGrayscaleImageStorage (Retired)");
+			sopClasses.put(UID.HardcopyColorImageStorageSOPClassRetired, "HardcopyColorImageStorage (Retired)");
+			sopClasses.put(UID.ComputedRadiographyImageStorage, "ComputedRadiographyImageStorage");
+			sopClasses.put(UID.DigitalXRayImageStorageForPresentation, "DigitalXRayImageStorageForPresentation");
+			sopClasses.put(UID.DigitalXRayImageStorageForProcessing, "DigitalXRayImageStorageForProcessing");
+			sopClasses.put(UID.DigitalMammographyXRayImageStorageForPresentation, "DigitalMammographyXRayImageStorageForPresentation");
+			sopClasses.put(UID.DigitalMammographyXRayImageStorageForProcessing, "DigitalMammographyXRayImageStorageForProcessing");
+			sopClasses.put(UID.DigitalIntraOralXRayImageStorageForPresentation, "DigitalIntraoralXRayImageStorageForPresentation");
+			sopClasses.put(UID.DigitalIntraOralXRayImageStorageForProcessing, "DigitalIntraoralXRayImageStorageForProcessing");
+			sopClasses.put(UID.StandaloneModalityLUTStorageRetired, "StandaloneModalityLUTStorage (Retired)");
+			sopClasses.put(UID.EncapsulatedPDFStorage, "EncapsulatedPDFStorage");
+			sopClasses.put(UID.StandaloneVOILUTStorageRetired, "StandaloneVOILUTStorage (Retired)");
+			sopClasses.put(UID.GrayscaleSoftcopyPresentationStateStorageSOPClass, "GrayscaleSoftcopyPresentationStateStorage");
+			sopClasses.put(UID.ColorSoftcopyPresentationStateStorageSOPClass, "ColorSoftcopyPresentationStateStorage");
+			sopClasses.put(UID.PseudoColorSoftcopyPresentationStateStorageSOPClass, "PseudoColorSoftcopyPresentationStateStorage");
+			sopClasses.put(UID.BlendingSoftcopyPresentationStateStorageSOPClass, "BlendingSoftcopyPresentationStateStorage");
+			sopClasses.put(UID.XRayAngiographicImageStorage, "XRayAngiographicImageStorage");
+			sopClasses.put(UID.EnhancedXAImageStorage, "EnhancedXAImageStorage");
+			sopClasses.put(UID.XRayRadiofluoroscopicImageStorage, "XRayRadiofluoroscopicImageStorage");
+			sopClasses.put(UID.EnhancedXRFImageStorage, "EnhancedXRFImageStorage");
+			sopClasses.put(UID.XRayAngiographicBiPlaneImageStorageRetired, "XRayAngiographicBiPlaneImageStorage (Retired)");
+			sopClasses.put(UID.PositronEmissionTomographyImageStorage, "PositronEmissionTomographyImageStorage");
+			sopClasses.put(UID.StandalonePETCurveStorageRetired, "StandalonePETCurveStorage (Retired)");
+			sopClasses.put(UID.CTImageStorage, "CTImageStorage");
+			sopClasses.put(UID.EnhancedCTImageStorage, "EnhancedCTImageStorage");
+			sopClasses.put(UID.NuclearMedicineImageStorage, "NuclearMedicineImageStorage");
+			sopClasses.put(UID.UltrasoundMultiFrameImageStorageRetired, "UltrasoundMultiframeImageStorage (Retired)");
+			sopClasses.put(UID.UltrasoundMultiFrameImageStorage, "UltrasoundMultiframeImageStorage");
+			sopClasses.put(UID.MRImageStorage, "MRImageStorage");
+			sopClasses.put(UID.EnhancedMRImageStorage, "EnhancedMRImageStorage");
+			sopClasses.put(UID.MRSpectroscopyStorage, "MRSpectroscopyStorage");
+			sopClasses.put(UID.RTImageStorage, "RTImageStorage");
+			sopClasses.put(UID.RTDoseStorage, "RTDoseStorage");
+			sopClasses.put(UID.RTStructureSetStorage, "RTStructureSetStorage");
+			sopClasses.put(UID.RTBeamsTreatmentRecordStorage, "RTBeamsTreatmentRecordStorage");
+			sopClasses.put(UID.RTPlanStorage, "RTPlanStorage");
+			sopClasses.put(UID.RTBrachyTreatmentRecordStorage, "RTBrachyTreatmentRecordStorage");
+			sopClasses.put(UID.RTTreatmentSummaryRecordStorage, "RTTreatmentSummaryRecordStorage");
+			sopClasses.put(UID.NuclearMedicineImageStorageRetired, "NuclearMedicineImageStorage (Retired)");
+			sopClasses.put(UID.UltrasoundImageStorageRetired, "UltrasoundImageStorage (Retired)");
+			sopClasses.put(UID.UltrasoundImageStorage, "UltrasoundImageStorage");
+			sopClasses.put(UID.RawDataStorage, "RawDataStorage");
+			sopClasses.put(UID.SpatialRegistrationStorage, "SpatialRegistrationStorage");
+			sopClasses.put(UID.SpatialFiducialsStorage, "SpatialFiducialsStorage");
+			sopClasses.put(UID.RealWorldValueMappingStorage, "RealWorldValueMappingStorage");
+			sopClasses.put(UID.SecondaryCaptureImageStorage, "SecondaryCaptureImageStorage");
+			sopClasses.put(UID.MultiFrameSingleBitSecondaryCaptureImageStorage, "MultiframeSingleBitSecondaryCaptureImageStorage");
+			sopClasses.put(UID.MultiFrameGrayscaleByteSecondaryCaptureImageStorage, "MultiframeGrayscaleByteSecondaryCaptureImageStorage");
+			sopClasses.put(UID.MultiFrameGrayscaleWordSecondaryCaptureImageStorage, "MultiframeGrayscaleWordSecondaryCaptureImageStorage");
+			sopClasses.put(UID.MultiFrameTrueColorSecondaryCaptureImageStorage, "MultiframeTrueColorSecondaryCaptureImageStorage");
+			sopClasses.put(UID.VLImageStorageTrialRetired, "VLImageStorage (Retired)");
+			sopClasses.put(UID.VLEndoscopicImageStorage, "VLEndoscopicImageStorage");
+			sopClasses.put(UID.VideoEndoscopicImageStorage, "VideoEndoscopicImageStorage");
+			sopClasses.put(UID.VLMicroscopicImageStorage, "VLMicroscopicImageStorage");
+			sopClasses.put(UID.VideoMicroscopicImageStorage, "VideoMicroscopicImageStorage");
+			sopClasses.put(UID.VLSlideCoordinatesMicroscopicImageStorage, "VLSlideCoordinatesMicroscopicImageStorage");
+			sopClasses.put(UID.VLPhotographicImageStorage, "VLPhotographicImageStorage");
+			sopClasses.put(UID.VideoPhotographicImageStorage, "VideoPhotographicImageStorage");
+			sopClasses.put(UID.OphthalmicPhotography8BitImageStorage, "OphthalmicPhotography8BitImageStorage");
+			sopClasses.put(UID.OphthalmicPhotography16BitImageStorage, "OphthalmicPhotography16BitImageStorage");
+			sopClasses.put(UID.StereometricRelationshipStorage, "StereometricRelationshipStorage");
+			sopClasses.put(UID.VLMultiFrameImageStorageTrialRetired, "VLMultiframeImageStorage (Retired)");
+			sopClasses.put(UID.StandaloneOverlayStorageRetired, "StandaloneOverlayStorage (Retired)");
+			sopClasses.put(UID.BasicTextSRStorage, "BasicTextSR");
+			sopClasses.put(UID.EnhancedSRStorage, "EnhancedSR");
+			sopClasses.put(UID.ComprehensiveSRStorage, "ComprehensiveSR");
+			sopClasses.put(UID.ProcedureLogStorage, "ProcedureLogStorage");
+			sopClasses.put(UID.MammographyCADSRStorage, "MammographyCADSR");
+			sopClasses.put(UID.KeyObjectSelectionDocumentStorage, "KeyObjectSelectionDocument");
+			sopClasses.put(UID.ChestCADSRStorage,  "ChestCADSR");
+			sopClasses.put(UID.StandaloneCurveStorageRetired, "StandaloneCurveStorage (Retired)");
+			sopClasses.put(UID.GeneralECGWaveformStorage, "GeneralECGWaveformStorage");
+			sopClasses.put(UID.AmbulatoryECGWaveformStorage,  "AmbulatoryECGWaveformStorage");
+			sopClasses.put(UID.HemodynamicWaveformStorage, "HemodynamicWaveformStorage");
+			sopClasses.put(UID.CardiacElectrophysiologyWaveformStorage, "CardiacElectrophysiologyWaveformStorage");
+			sopClasses.put(UID.BasicVoiceAudioWaveformStorage, "BasicVoiceAudioWaveformStorage");
+			sopClasses.put(UID.HangingProtocolStorage, "HangingProtocolStorage");
+			sopClasses.put(UID.SiemensCSANonImageStorage, "SiemensCSANonImageStorage");
+                        sopClasses.put(UID.VLWholeSlideMicroscopyImageStorage, "VLWholeSlideMicroscopyImageStorage");
+                        sopClasses.put(UID.BreastTomosynthesisImageStorage, "BreastTomosynthesisImageStorage");
+
+			transferSettings.put(UID.ImplicitVRLittleEndian, "ImplicitVRLittleEndian");
+			transferSettings.put(UID.ExplicitVRLittleEndian, "ExplicitVRLittleEndian");
+			transferSettings.put(UID.DeflatedExplicitVRLittleEndian, "DeflatedExplicitVRLittleEndian");
+			transferSettings.put(UID.ExplicitVRBigEndian, "ExplicitVRBigEndian");
+			transferSettings.put(UID.JPEGLossless, "JPEG Lossless");
+			transferSettings.put(UID.JPEGLSLossless, "JPEG Lossless LS");
+			transferSettings.put(UID.JPEGLosslessNonHierarchical14, "JPEG Lossless, Non-Hierarchical (Process 14) ");
+			transferSettings.put(UID.JPEG2000LosslessOnly, "JPEG2000 Lossless Only");
+			transferSettings.put(UID.JPEGBaseline1, "JPEG Baseline 1");
+			transferSettings.put(UID.JPEGExtended24, "JPEG Extended (Process 2 & 4)");
+			transferSettings.put(UID.JPEGLSLossyNearLossless, "JPEG LS Lossy Near Lossless");
+			transferSettings.put(UID.JPEG2000, "JPEG2000");
+			transferSettings.put(UID.RLELossless, "RLE Lossless");
+			transferSettings.put(UID.MPEG2, "MPEG2");
+
+			transferSettingsIndex.put(UID.ImplicitVRLittleEndian, 0);
+			transferSettingsIndex.put(UID.ExplicitVRLittleEndian, 1);
+			transferSettingsIndex.put(UID.DeflatedExplicitVRLittleEndian, 2);
+			transferSettingsIndex.put(UID.ExplicitVRBigEndian, 3);
+			transferSettingsIndex.put(UID.JPEGLossless, 4);
+			transferSettingsIndex.put(UID.JPEGLSLossless, 5);
+			transferSettingsIndex.put(UID.JPEGLosslessNonHierarchical14, 6);
+			transferSettingsIndex.put(UID.JPEG2000LosslessOnly, 7);
+			transferSettingsIndex.put(UID.JPEGBaseline1, 8);
+			transferSettingsIndex.put(UID.JPEGExtended24, 9);
+			transferSettingsIndex.put(UID.JPEGLSLossyNearLossless, 10);
+			transferSettingsIndex.put(UID.JPEG2000, 11);
+			transferSettingsIndex.put(UID.RLELossless, 12);
+			transferSettingsIndex.put(UID.MPEG2, 13);
+		}
+
+		/**
+		 * Returns the SOP Classes UID and "regular" name translation list.
+		 *
+		 * @return the SOP Classes UID and "regular" name translation list.
+		 */
+		public HashMap<String, String> getSOPClasses()
+		{
+			return sopClasses;
+		}
+
+		/**
+		 * Returns the TransferStorage UID and "regular" name translation list.
+		 *
+		 * @return the TransferStorage UID and "regular" name translation list.
+		 */
+		public HashMap<String, String> getTransferSettings()
+		{
+			return transferSettings;
+		}
+
+		/**
+		 * Returns the TransferStorage UID and their index on the TS object translation list.
+		 *
+		 * @return the TransferStorage UID and their index on the TS object translation list.
+		 */
+		public HashMap<String, Integer> getTransferSettingsIndex()
+		{
+			return transferSettingsIndex;
+		}
+
+		/**
+		 * Returns the current instance of this class.
+		 *
+		 * @return the current instance of this class.
+		 */
+		public static synchronized SOPClassSettings getInstance()
+		{
+			if (instance == null)
+				instance = new SOPClassSettings();
+
+			return instance;
+		}
+
+		/**
+		 * Returns the TransferStorage settings fo a SOP Class UID.
+		 *
+		 * @param sopClassUID the SOP Class UID.
+		 * @return the TransferStorage settings fo a SOP Class UID.
+		 */
+		public synchronized TransfersStorage getSOPClassSettings(String sopClassUID)
+		{
+			return sopList.getTS(sopClassUID);
+		}
+
+		/**
+		 * Defines all the settings values related to all SOP Classes UIDs.
+		 *
+		 * @param accepted if this SOP Class is accepted. Can be null and if so, the target accepted value will remain the same.
+		 * @param allowedTransStore a HashMap indicating which TransferStore UIDs are accepted.
+		 */
+		public synchronized void setAllSOPClassesSettings(Boolean accepted, HashMap<String, Boolean> allowedTransStore)
+		{
+			// for all the sop classes
+			List keys = sopList.getKeys();
+			for (int i = 0; i < keys.size(); i++)
+			{
+				// get the sop class uid
+				String sopClassUID = (String) keys.get(i);
+
+				// apply the settings
+				setSOPClassSettings(sopClassUID, accepted, allowedTransStore);
+			}
+		}
+
+		/**
+		 * Defines all the settings values related to a SOP Class UID.
+		 *
+		 * @param sopClassUID the SOP Class UID.
+		 * @param accepted if this SOP Class is accepted. Can be null and if so, the target accepted value will remain the same.
+		 * @param allowedTransStore a HashMap indicating which TransferStore UIDs are accepted.
+		 */
+		public synchronized void setSOPClassSettings(String sopClassUID, Boolean accepted, HashMap<String, Boolean> allowedTransStore)
+		{
+			// get the transfer storage object for this sop class uid
+			TransfersStorage trans = sopList.getTS(sopClassUID);
+
+			// apply the settings
+			setTransferStorageSettings(trans, accepted, allowedTransStore);
+		}
+
+		/**
+		 * Defines all the settings values related to a TransferStorage object.
+		 *
+		 * @param trans the TransferStorage object.
+		 * @param accepted if this SOP Class is accepted. Can be null and if so, the target accepted value will remain the same.
+		 * @param allowedTransStore a HashMap indicating which TransferStore UIDs are accepted.
+		 */
+		public synchronized void setTransferStorageSettings(TransfersStorage trans, Boolean accepted, HashMap<String, Boolean> allowedTransStore)
+		{
+			// accept this sop class, if necessary
+			if (accepted != null)
+				trans.setAccepted(accepted.booleanValue());
+			// accept all the transfer storage settings
+			for (String transStoreUID : transferSettings.keySet())
+			{
+				// skip this transfer store uid if it is not referenced on the allowedTransStore // FIXME is this right, or should non-defined entries be set as false?!?
+				if (! allowedTransStore.containsKey(transStoreUID))
+					continue;
+
+				trans.setTS(allowedTransStore.get(transStoreUID).booleanValue(), transferSettingsIndex.get(transStoreUID).intValue());
+			}
+		}
+	}
+
+	/**
+	 * Returns a StaticDataTable containing the TransferStorages for a
+	 * specific SOP Class UID.
+	 *
+	 * @param sopClassUID a SOP Class UID.
+	 * @return an Object array containing as first elements a Boolean object
+	 * indicating if this SOP Class is accepted and as second element a
+	 * StaticDataTable that contains the TransferStorages for this specific
+	 * SOP Class UID.
+	 */
+	public Object[] getTransferSettingsForSOPClass(String sopClassUID)
+	{
+		SOPClassSettings sops = SOPClassSettings.getInstance();
+		TransfersStorage ts = sops.getSOPClassSettings(sopClassUID);
+
+		// this settings will be returned on a StaticDataTable, to guarantee that the user does not change the entry count and only their values
+		StaticDataTable table = new StaticDataTable(1, sops.getTransferSettings().size());
+		// for each setting on the transfer storage settings...
+		int i = 0;
+		for (Map.Entry<String, String> entry : sops.getTransferSettings().entrySet())
+		{
+			// get its UID, "visual/regular" name and index (relative to the TS settings array)
+			String uid = entry.getKey();
+			String name = entry.getValue();
+			int index = sops.getTransferSettingsIndex().get(uid).intValue();
+
+			// create a HintedCheckbox with the info gotten above and the current value of the setting
+			CheckboxWithHint box = new CheckboxWithHint(ts.getTS()[index], name, uid);
+			// and add the checkbox to the data table
+			table.setCellData(i, 0, box);
+
+			i++;
+		}
+
+		// mount the return object array
+		Object[] result = new Object[2];
+		// and add the proper objects to it
+		result[0] = new Boolean(ts.getAccepted());
+		result[1] = table;
+
+		return result;
+	}
+
+	/**
+	 * Returns a StaticDataTable containing the TransferStorages settings
+	 * for all SOP Classes UIDs.
+	 *
+	 * @return an Object array containing as first elements a Boolean object
+	 * indicating if all SOP Classes are accepted and as second element a
+	 * StaticDataTable that contains the TransferStorages for all SOP Classes
+	 * UIDs.
+	 */
+	public Object[] getTransferSettingsForAllSOPClasses()
+	{
+		SOPClassSettings sops = SOPClassSettings.getInstance();
+
+		// get the first SOP Class UID // FIXME using the first SOP Class settings as global does not accurately represent the common settings for all SOP classes, but it's close enough (if they get applied :) )
+		String sopClassUID = sops.getSOPClasses().entrySet().iterator().next().getKey();
+		// and its TransferStorage settings
+		TransfersStorage ts = sops.getSOPClassSettings(sopClassUID);
+
+		// this settings will be returned on a StaticDataTable, to guarantee that the user does not change the entry count and only their values
+		StaticDataTable table = new StaticDataTable(1, sops.getTransferSettings().size());
+		table.setColumnName(0, "Transfer Storage");
+		// for each setting on the transfer storage settings...
+		int i = 0;
+		for (Map.Entry<String, String> entry : sops.getTransferSettings().entrySet())
+		{
+			// get its UID, "visual/regular" name and index (relative to the TS settings array)
+			String uid = entry.getKey();
+			String name = entry.getValue();
+			int index = sops.getTransferSettingsIndex().get(uid).intValue();
+
+			// create a HintedCheckbox with the info gotten above and the current value of the setting
+			CheckboxWithHint box = new CheckboxWithHint(ts.getTS()[index], name, uid);
+			// and add the checkbox to the data table
+			table.setCellData(i, 0, box);
+
+			i++;
+		}
+
+		// mount the return object array
+		Object[] result = new Object[2];
+		// and add the proper objects to it
+		result[0] = new Boolean(ts.getAccepted());
+		result[1] = table;
+
+		return result;
+	}
+
+	/**
+	 * Applies the Transfer Storage settings present on a StaticDataTable to
+	 * a specific SOP Class UID.
+	 *
+	 * @param sopClassUID the target SOP Class UID.
+	 * @param accepted if the SOP Class UID is accepted. Can be null and if so, the target accepted value will remain the same.
+	 * @param table a StaticDataTable with the Transfer Storage settings.
+	 */
+	public void setTransferSettingsForSOPClass(String sopClassUID, Boolean accepted, StaticDataTable table)
+	{
+		SOPClassSettings sops = SOPClassSettings.getInstance();
+		TransfersStorage ts = sops.getSOPClassSettings(sopClassUID);
+
+		// for each transfer storage setting on the datatable...
+		for (int i = 0 ; i < table.getRowCount(); i++)
+		{
+			// get the current row/cell setting
+			CheckboxWithHint box = (CheckboxWithHint) table.getCellData(i, 0);
+
+			// get its UID and index (relative to the TS settings array)
+			String uid = box.getHint();
+			int index = sops.getTransferSettingsIndex().get(uid).intValue();
+
+			// set the transfer storge setting value
+			ts.setTS(box.isChecked(), index);
+			if (accepted != null)
+				ts.setAccepted(accepted.booleanValue());
+		}
+	}
+
+	/**
+	 * Applies the Transfer Storage settings present on a StaticDataTable to
+	 * all SOP Classes UIDs.
+	 *
+	 * @param accepted if all SOP Classes UIDs are accepted. Can be null and if so, the target accepted value will remain the same.
+	 * @param table a StaticDataTable with the Transfer Storage settings.
+	 */
+	public void setTransferSettingsForAllSOPClasses(Boolean accepted, StaticDataTable table)
+	{
+		SOPClassSettings sops = SOPClassSettings.getInstance();
+
+		HashMap<String, Boolean> allowed = new HashMap<String, Boolean>();
+
+		// for each transfer storage setting on the datatable...
+		for (int i = 0 ; i < table.getRowCount(); i++)
+		{
+			// get the current row/cell setting
+			CheckboxWithHint box = (CheckboxWithHint) table.getCellData(i, 0);
+
+			// get its UID
+			String uid = box.getHint();
+
+			allowed.put(uid, new Boolean(box.isChecked()));
+		}
+
+		// set the transfer storage settings
+		sops.setAllSOPClassesSettings(accepted, allowed);
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Indexer.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Indexer.java
new file mode 100644
index 0000000..72988c0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Indexer.java
@@ -0,0 +1,275 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.management;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.slf4j.LoggerFactory;
+
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * A wrapper used to manage the indexer remotely through the web environment/app.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Indexer{
+	/**
+	 * The current instance of this class.
+	 */
+	private static Indexer instance;
+
+	/**
+	 * Pointer to a object that maintain the IndexEngine information.
+	 */
+
+	private static ServerSettings cfg;
+        
+        private static List<Task> taskList;
+
+
+	/**
+	 * The name of the setting that indicates the Dicoogle Directory Monitorization.
+	 */
+	public static final String SETTING_DIRECTORY_MONITORIZATION_NAME = "Dicoogle Directory Monitorization";
+	/**
+	 * The name of the setting that indicates the Indexing Effort.
+	 */
+	public static final String SETTING_INDEXING_EFFORT_NAME = "Indexing Effort";
+	/**
+	 * The name of the setting that indicates the Thumbnails Size.
+	 */
+	public static final String SETTING_THUMBNAILS_SIZE_NAME = "Thumbnails Size";
+	/**
+	 * The name of the setting that indicates if Thumbnails are to be Saved.
+	 */
+	public static final String SETTING_SAVE_THUMBNAILS_NAME = "Save Thumbnails";
+	/**
+	 * The name of the setting that indicates if ZIP files are to be Indexed.
+	 */
+	public static final String SETTING_INDEX_ZIP_FILES_NAME = "Index ZIP Files";
+
+	/**
+	 * The help of the Indexing Effort setting.
+	 */
+	public static final String SETTING_INDEXING_EFFORT_HELP = "How agressive should the indexing effort be.\n\n0 - Lower\n100 - Intensive";
+
+	private Indexer(){
+		
+		cfg = ServerSettings.getInstance();
+                taskList = new ArrayList<Task>();
+	}
+
+	/**
+	 * Returns the current instance of this class.
+	 *
+	 * @return the current instance of this class.
+	 */
+	public synchronized static Indexer getInstance(){
+		if (instance == null)
+			instance = new Indexer();
+
+		return instance;
+	}
+
+	/**
+	 * Returns a Map containing the current settings.
+	 *
+	 * @return a Map containing the current settings.
+	 */
+	public HashMap<String, Object> getSettings()
+	{
+		HashMap<String, Object> settings = new HashMap<String, Object>();
+
+		//settings.put(SETTING_DIRECTORY_MONITORIZATION_NAME, new ServerDirectoryPath(cfg.getDicoogleDir()));
+		//settings.put(SETTING_INDEXING_EFFORT_NAME, new RangeInteger(0, 100, cfg.getIndexerEffort()));
+		settings.put(SETTING_THUMBNAILS_SIZE_NAME, cfg.getThumbnailsMatrix()); // TODO add more descritive type
+		settings.put(SETTING_SAVE_THUMBNAILS_NAME, cfg.getSaveThumbnails());
+		settings.put(SETTING_INDEX_ZIP_FILES_NAME, cfg.isIndexZIPFiles());
+
+		return settings;
+	}
+
+	/**
+	 * Tries to set the supplied settings as the new settings.
+	 *
+	 * @param settings a Map containing the new settings.
+	 * @return true if all settings were successfully changed to the ones supplied, false otherwise (no settings changed).
+	 */
+	public boolean setSettings(HashMap<String, Object> settings)
+	{
+		// validate the settings
+		boolean valid = false;
+		try
+		{
+			valid = trySettings(settings);
+		}
+		catch (/*InvalidSettingValueException ex*/ Exception ex)
+		{
+			// at least one of the setting is invalid, abort
+			return false;
+		}
+		if (! valid) //settings not valid due to unknown reason, also abort
+			return false;
+
+		// all the settings were correctly validated, so apply them all
+		//cfg.setDicoogleDir(((ServerDirectoryPath) settings.get(SETTING_DIRECTORY_MONITORIZATION_NAME)).getPath());
+		//cfg.setIndexerEffort(((RangeInteger) settings.get(SETTING_INDEXING_EFFORT_NAME)).getValue());
+		cfg.setThumbnailsMatrix((String) settings.get(SETTING_THUMBNAILS_SIZE_NAME));
+		cfg.setSaveThumbnails(((Boolean) settings.get(SETTING_SAVE_THUMBNAILS_NAME)).booleanValue());
+		cfg.setIndexZIPFiles(((Boolean) settings.get(SETTING_INDEX_ZIP_FILES_NAME)).booleanValue());
+
+		// return success
+		return true;
+	}
+
+	/**
+	 * Validates the settings supplied and checks if they are valid ones.
+	 *
+	 * @param map a Map containing the settings.
+	 * @return true if all the settings are valid.
+	 * @throws InvalidSettingValueException if at least one of the settings is invalid.
+	 */
+	public boolean trySettings(HashMap<String, Object> map) /*throws InvalidSettingValueException*/
+	{
+		// TODO remmember to check for null, all the params are supplied, all have valid types, and oly then all have valid values
+
+		return true;
+	}
+
+	/**
+	 * Returns the settings help.
+	 *
+	 * @return a HashMap containing the setting help.
+	 */
+	public HashMap<String, String> getSettingsHelp(){
+		HashMap<String, String> settings = new HashMap<String, String>();
+		// right now this is the only settingg that needs some help describing it
+		settings.put(SETTING_INDEXING_EFFORT_NAME, SETTING_INDEXING_EFFORT_HELP);
+		return settings;
+	}
+
+	/**
+	 * Starts the indexing process.
+	 */
+	public void startIndexing(){
+		File dir = new File(cfg.getDicoogleDir());
+		if ((dir == null) || (! dir.isDirectory()))
+			return;
+		String path = dir.getAbsolutePath();
+		if (path == null)
+			return;
+                
+                URI uri = null;
+                try {
+                    uri = new URI(path);
+                } catch (URISyntaxException ex) {
+                    LoggerFactory.getLogger(Indexer.class).error(ex.getMessage(), ex);
+                }
+                if (uri != null)
+                {
+                    List<Task<Report>> tmpList = PluginController.getInstance().index(uri);
+                    
+                    for (Task _t : tmpList)
+                    {
+                        taskList.add(_t);
+                    }
+                    
+                }
+	}
+
+	/**
+	 * Stops the indexing process.
+	 */
+	public void stopIndexing()
+	{
+            
+            for (Task _t : taskList)
+            {
+                        _t.cancel(true);
+            }
+                    
+	}
+
+	/**
+	 * Returns if the Index Engine is currently indexing.
+	 *
+	 * @return if the Index Engine is currently indexing.
+	 */
+	public boolean isIndexing(){
+		
+            
+            int numberOfActiveTasks = 0;
+            for (Task _t : taskList)
+            {
+                if (_t.getProgress()<100)
+                {
+                    numberOfActiveTasks++;
+                }
+            }
+            return numberOfActiveTasks!=0;
+	}
+
+	/**
+	 * Returns the current progress (percentual) of the indexing operation.
+	 *
+	 * @return the current progress (percentual) of the indexing operation.
+	 */
+	public int indexingPercentCompleted(){
+		
+            
+            int numberOfTasks = 0;
+            float all=0;
+            for (Task _t : taskList)
+            {
+                
+                all = all + _t.getProgress();
+                numberOfTasks++;
+                
+            }
+            return (int)(all*100.0/(100*numberOfTasks));
+            
+	}
+
+	/**
+	 * Sets the Dicoogle indexing path.
+	 *
+	 * @param path the Dicoogle indexing path.
+	 */
+	public void setDicooglePath(String path){
+		cfg.setDicoogleDir(path);
+	}
+
+	/**
+	 * Gets the Dicoogle indexing path.
+	 *
+	 * @return the Dicoogle indexing path.
+	 */
+	public String getDicooglePath(){
+		return cfg.getDicoogleDir();
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Services.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Services.java
new file mode 100644
index 0000000..421de33
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/management/Services.java
@@ -0,0 +1,1196 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.management;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.HashMap;
+
+import pt.ua.dicoogle.core.XMLSupport;
+import pt.ua.dicoogle.core.ServerSettings;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import pt.ua.dicoogle.server.ControlServices;
+import pt.ua.dicoogle.plugins.PluginController;
+import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
+import pt.ua.dicoogle.sdk.settings.Utils;
+
+// FIXME do the procedures of this class need to be synchronized?!?
+/**
+ * A wrapper used to manage the services and plugins remotely through the web
+ * environment/app.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Services {
+
+    /**
+     * The current instance of this class.
+     */
+    private static Services instance;
+    /**
+     * Pointers to the objects that maintain the services and plugins
+     * information.
+     */
+    private static ControlServices svcs;
+    private static PluginController plgs;
+    /**
+     * Types of actions to perform.
+     */
+    public static final int SVC_NO_ACTION = 0;
+    public static final int SVC_START = 1;
+    public static final int SVC_STOP = 2;
+    public static final int SVC_INIT_START = 3;
+    public static final int SVC_SET_PORT = 4;
+    public static final int SVC_SET_SETTINGS = 5;
+    /**
+     * Textual representation of the actions available.
+     */
+    public static final String ACTION_START = "start";
+    public static final String ACTION_STOP = "stop";
+    public static final String ACTION_INIT_START = "init-start";
+    public static final String ACTION_SET_PORT = "set-port";
+    public static final String ACTION_SET_ADVANCED_SETTINGS = "set-settings";
+    /**
+     * Textural representation of the params available.
+     */
+    public static final String PARAM_ACTION = "action";
+    public static final String PARAM_SERVICE = "service";
+    public static final String PARAM_INIT_START = "init-start";
+    public static final String PARAM_PORT = "port";
+    /**
+     * The embedded services name.
+     */
+    public static final String storageName = "Storage";
+    public static final String queryRetrieveName = "Query Retrieve";
+    public static final String webServicesName = "Web Services";
+    public static final String webServerName = "Web Server";
+    public static final String remoteGUIName = "Remote GUI";
+    /**
+     * The results indicating what was wrong with a performAction call.
+     */
+    public static final int RES_NO_ACTION = 0;
+    public static final int RES_INVALID_ACTION = 1;
+    public static final int RES_NO_SERVICE_NAME = 2;
+    public static final int RES_INVALID_SERVICE_NAME = 3;
+    public static final int RES_INVALID_ACTION_PARAMETER = 4;
+    public static final int RES_WARNING = 5;
+    public static final int RES_OK = 6;
+    /**
+     * The object responsible for saving the settings between server inits.
+     */
+    private XMLSupport xmlSupport;
+    /**
+     * Server settings container.
+     */
+    private ServerSettings cfgs;
+
+    private Services() {
+        svcs = ControlServices.getInstance();
+        plgs = PluginController.getInstance();
+
+        cfgs = ServerSettings.getInstance();
+        xmlSupport = new XMLSupport();
+    }
+
+    /**
+     * Returns the current instance of this class.
+     *
+     * @return the current instance of this class.
+     */
+    public synchronized static Services getInstance() {
+        if (instance == null) {
+            instance = new Services();
+        }
+
+        return instance;
+    }
+
+    /**
+     * This converts and applies the new textual values into the
+     * originalSettings HashMap, taking into account their original class/type.
+     * Only the settings that exist on both Maps are updated, this avoid invalid
+     * settings and Class type injections from happening.
+     *
+     * @param originalSettings the original advanced/internal settings of a
+     * plugin or service.
+     * @param newSettings the new settings to apply.
+     * @return the originalSettings HashMap with the new values in place (you
+     * can use the reference passed as originalSettings instead if you want,
+     * they will allways be the same).
+     */
+    public HashMap<String, Object> processAdvancedSettings(HashMap<String, Object> originalSettings, HashMap<String, String[]> newSettings) {
+        for (Map.Entry<String, Object> setting : originalSettings.entrySet()) {
+            String name = Utils.getHTMLElementIDFromString(setting.getKey()); // NOTE remmember that the setting name is "kinda encoded" (and not in the URLEncode way, that's handled automagically)
+            Object value = setting.getValue();
+
+            if (newSettings.containsKey(name)) // if the setting is found on the request try to update its value (maintaining the same type ofc)
+            {
+                String[] newValue = newSettings.get(name);
+
+                if (value != null) {
+                    // parse the value depending on its class
+                    if (value.getClass().equals(Integer.class)) {
+                        value = Integer.valueOf(newValue[0]);
+                    } else if (value.getClass().equals(Float.class)) {
+                        value = Float.valueOf(newValue[0]);
+                    } else if (value.getClass().equals(Boolean.class)) {
+                        value = Boolean.valueOf(Utils.parseCheckBoxValue(newValue[0]));
+                    } /*else if (value.getClass().equals(ServerDirectoryPath.class))
+                     value = ServerDirectoryPath.fromHTTPParams((ServerDirectoryPath) value, newSettings, name);*/ 
+                    //else if (value instanceof GenericSetting) {
+                       // value = ((GenericSetting) value).fromHTTPParams(newSettings, name);
+                //    } 
+                    else // String or unrecognized class
+                    {
+                        value = newValue[0];
+                    }
+
+                    setting.setValue(value);
+                } else // null is treated as String
+                {
+                    value = newValue[0];
+
+                    setting.setValue(value);
+                }
+
+            } else // if the setting was not found check if it's a Boolean one, this is a FIX because browsers omit unchecked checkboxes on form action
+            {
+                if (value.getClass().equals(Boolean.class)) {
+                    setting.setValue(false);
+                }
+            }
+        }
+
+        return originalSettings; // just for easier use
+    }
+
+    /**
+     * Performs a certain action to a service or plugin.
+     *
+     * @param action the action to perform.
+     * @param svcName the name of the service or plugin to perform the action
+     * at.
+     * @param initStart the init-start param value.
+     * @param port the set-port param value.
+     * @param advSettings a HashMap with all the advanced settings and their
+     * values.
+     * @return an int value indicating what was wrong with the call (see
+     * Services.RES_* for values/name pairs)
+     */
+    @Deprecated
+    public int performAction(int action, String svcName, boolean initStart, int port, HashMap<String, String[]> advSettings) {
+        if ((svcName == null) || svcName.trim().isEmpty()) {
+            return RES_NO_SERVICE_NAME;
+        }
+
+        try {
+            switch (action) {
+                case SVC_START:
+                    if (svcName.equalsIgnoreCase(webServerName)) {
+                        svcs.startWebServer();
+                        return RES_OK;
+                    } else {
+                        if (svcName.equalsIgnoreCase(webServicesName)) {
+
+                            svcs.startWebServices();
+                            return RES_OK;
+                        } else {
+                            if (svcName.equalsIgnoreCase(storageName)) {
+                                svcs.startStorage();
+                                return RES_OK;
+                            } else {
+                                if (svcName.equalsIgnoreCase(queryRetrieveName)) {
+                                    svcs.startQueryRetrieve();
+                                    return RES_OK;
+                                } else {
+                                	//TODO: DELETED
+                                    /*for (String plug : plgs.getPluginsNames()) {
+                                        if (plug.equalsIgnoreCase(svcName)) {
+                                            svcs.startPlugin(svcName);
+                                            return RES_OK;
+                                        }
+                                    }*/
+
+                                    return RES_INVALID_SERVICE_NAME;
+                                }
+                            }
+                        }
+                    }
+
+                case SVC_STOP:
+                    if (svcName.equalsIgnoreCase(webServerName)) {
+                        svcs.stopWebServer();
+                        return RES_OK;
+                    } else {
+                        if (svcName.equalsIgnoreCase(webServicesName)) {
+
+                            svcs.stopWebServices();
+                            return RES_OK;
+                        } else {
+                            if (svcName.equalsIgnoreCase(storageName)) {
+                                svcs.stopStorage();
+                                return RES_OK;
+                            } else {
+                                if (svcName.equalsIgnoreCase(queryRetrieveName)) {
+                                    svcs.stopQueryRetrieve();
+                                    return RES_OK;
+                                } else {
+                                	//TODO: DELETED
+                                    /*for (String plug : plgs.getPluginsNames()) {
+                                        if (svcName.equalsIgnoreCase(plug)) {
+                                            svcs.stopPlugin(svcName);
+                                            return RES_OK;
+                                        }
+                                    }*/
+
+                                    return RES_INVALID_SERVICE_NAME;
+                                }
+                            }
+                        }
+                    }
+
+                case SVC_INIT_START:
+                    if (svcName.equalsIgnoreCase(webServerName)) {
+                        setWebServerStart(initStart);
+                        return RES_OK;
+                    } else {
+                        if (svcName.equalsIgnoreCase(webServicesName)) {
+
+                            setWebServicesStart(initStart);
+                            return RES_OK;
+                        } else {
+                            if (svcName.equalsIgnoreCase(storageName)) {
+                                setStorageStart(initStart);
+                                return RES_OK;
+                            } else {
+                                if (svcName.equalsIgnoreCase(queryRetrieveName)) {
+                                    setQueryRetrieveStart(initStart);
+                                    return RES_OK;
+                                } else {
+                                	//TODO: DELETED
+                                    /*for (String plug : plgs.getPluginsNames()) {
+                                        if (svcName.equalsIgnoreCase(plug)) {
+                                            cfgs.setAutoStartPlugin(svcName, initStart);
+                                            return RES_OK;
+                                        }
+                                    }*/
+
+                                    return RES_INVALID_SERVICE_NAME;
+                                }
+                            }
+                        }
+                    }
+
+                case SVC_SET_PORT: {
+                    if ((port < 0) || (port > 65535)) {
+                        return RES_INVALID_ACTION_PARAMETER;
+                    }
+
+                    if (svcName.equalsIgnoreCase(webServerName)) {
+                        setWebServerPort(port);
+                        return RES_OK;
+                    } else {
+                        if (svcName.equalsIgnoreCase(webServicesName)) {
+
+                            setWebServicesPort(port);
+                            return RES_OK;
+                        } else {
+                            if (svcName.equalsIgnoreCase(storageName)) {
+                                setStoragePort(port);
+                                return RES_OK;
+                            } else {
+                                if (svcName.equalsIgnoreCase(queryRetrieveName)) {
+                                    setQueryRetrievePort(port);
+                                    return RES_OK;
+                                } else {
+                                    if (svcName.equalsIgnoreCase(remoteGUIName)) {
+                                        setRemoteGUIPort(port);
+                                        return RES_OK;
+                                    } else {
+                                        // TODO for plugins
+
+                                        return RES_INVALID_SERVICE_NAME;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                case SVC_SET_SETTINGS:
+                    if (advSettings == null || advSettings.isEmpty()) {
+                        return RES_INVALID_ACTION_PARAMETER;
+                    } else {
+                        if (svcName.equalsIgnoreCase(storageName)) {
+                            HashMap<String, Object> settings = cfgs.getStorageSettings();
+
+                            processAdvancedSettings(settings, advSettings);
+
+                            // try to apply the settings
+                            if (cfgs.tryStorageSettings(settings)) {
+                                cfgs.setStorageSettings(settings);
+
+                                saveSettings();
+
+                                return RES_OK;
+                            } else {
+                                return RES_INVALID_ACTION_PARAMETER;
+                            }
+                        } else {
+                            if (svcName.equalsIgnoreCase(queryRetrieveName)) {
+                                HashMap<String, Object> settings = cfgs.getQueryRetrieveSettings();
+
+                                processAdvancedSettings(settings, advSettings);
+
+                                // try to apply the settings
+                                if (cfgs.tryQueryRetrieveSettings(settings)) {
+                                    cfgs.setQueryRetrieveSettings(settings);
+
+                                    saveSettings();
+
+                                    return RES_OK;
+                                } else {
+                                    return RES_INVALID_ACTION_PARAMETER;
+                                }
+                            } else {
+                                if (svcName.equalsIgnoreCase(remoteGUIName)) {
+                                    HashMap<String, Object> settings = cfgs.getRGUISettings();
+
+                                    processAdvancedSettings(settings, advSettings);
+
+                                    // try to apply the settings
+                                    if (cfgs.tryRGUISettings(settings)) {
+                                        cfgs.setRGUISettings(settings);
+
+                                        saveSettings();
+
+                                        return RES_OK;
+                                    } else {
+                                        return RES_INVALID_ACTION_PARAMETER;
+                                    }
+                                } else {
+                                    if (plgs.hasAdvancedSettings(svcName)) {
+                                        //TODO: DELETED
+                                    	//HashMap<String, Object> settings = plgs.getAdvancedSettings(svcName);
+
+                                        //processAdvancedSettings(settings, advSettings);
+
+
+                                        // try to apply the settings
+                                        if (/*plgs.trySettings(svcName, settings)*/true) {
+                                            //plgs.setSettings(svcName, settings);
+
+                                            //plgs.saveSettings();
+
+                                            return RES_OK;
+                                        } else {
+                                            return RES_INVALID_ACTION_PARAMETER;
+                                        }
+                                    }
+
+                                    return RES_INVALID_SERVICE_NAME;
+                                }
+                            }
+                        }
+                    }
+
+                case SVC_NO_ACTION:
+                default:
+                    return RES_INVALID_ACTION;
+            }
+        } catch (IOException ex) {
+            return RES_WARNING;
+        }
+    }
+
+    /**
+     * Performs a certain action to a service or plugin, and save the settings
+     * if needed.
+     *
+     * @param request the request object.
+     * @return an int value indicating what was wrong with the call (see
+     * Services.RES_* for values/name pairs).
+     */
+    public int performAction(HttpServletRequest request) throws UnsupportedEncodingException {
+        // set proper encoding on the request
+        request.setCharacterEncoding("UTF-8");
+
+        // get the action to take
+        String action = request.getParameter(PARAM_ACTION);
+
+        // check if it is a valid action
+        if (action == null) {
+            return RES_NO_ACTION;
+        }
+
+        // get the name of the service/plugin to execute the action at
+        String svcName = request.getParameter(PARAM_SERVICE);
+
+        int portNumber = 0;
+        boolean initOnStart = false;
+        HashMap<String, String[]> advSettings = new HashMap<>();
+
+        int act = SVC_NO_ACTION;
+        if (action.equalsIgnoreCase(ACTION_START)) {
+            act = SVC_START;
+        } else if (action.equalsIgnoreCase(ACTION_STOP)) {
+            act = SVC_STOP;
+        } else if (action.equalsIgnoreCase(ACTION_INIT_START)) {
+            initOnStart = Utils.parseCheckBoxValue(request.getParameter(PARAM_INIT_START));
+            act = SVC_INIT_START;
+        } else if (action.equalsIgnoreCase(ACTION_SET_PORT)) {
+            String port = request.getParameter(PARAM_PORT);
+
+            if (port == null || port.trim().isEmpty()) {
+                return RES_INVALID_ACTION_PARAMETER;
+            }
+
+            portNumber = Integer.parseInt(port);
+            act = SVC_SET_PORT;
+        } else if (action.equalsIgnoreCase(ACTION_SET_ADVANCED_SETTINGS)) {
+            // get all the settings and their values
+            Enumeration<String> params = request.getParameterNames();
+            while (params.hasMoreElements()) {
+                String name = params.nextElement();
+
+                // ignore the main params (the ones that go us here)
+                if (name.equalsIgnoreCase(PARAM_ACTION) || name.equalsIgnoreCase(PARAM_SERVICE)) {
+                    continue;
+                }
+
+                String[] value = request.getParameterValues(name);
+
+                advSettings.put(name, value);
+            }
+
+            act = SVC_SET_SETTINGS;
+        } else {
+            return RES_INVALID_ACTION;
+        }
+
+        // execute the action requested
+        int result = performAction(act, svcName, initOnStart, portNumber, advSettings);
+
+        // save the settings if needed
+        if ((result == RES_OK) && ((act == SVC_INIT_START) || (act == SVC_SET_PORT))) {
+            saveSettings();
+        }
+
+        // return the performAction result
+        return result;
+    }
+
+    /**
+     * Processes a request from a servlet to perform an action on a service or
+     * plugin.
+     *
+     * @param request the servlet request object.
+     * @param response the servlet response object.
+     * @throws IOException if there was an error while attempting to perform the
+     * requested action.
+     */
+    public void processServletRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        // try to perform the action
+        int result = performAction(request);
+
+        // check the result and repond accordingly
+        switch (result) {
+            case RES_OK:
+                response.setStatus(HttpServletResponse.SC_OK);
+                break;
+
+            case RES_NO_ACTION:
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No action defined!");
+                break;
+
+            case RES_INVALID_ACTION:
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid action!");
+                break;
+
+            case RES_NO_SERVICE_NAME:
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No service/plugin name defined!");
+                break;
+
+            case RES_INVALID_SERVICE_NAME:
+                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid service/plugin name!");
+                break;
+
+            case RES_WARNING:
+            default:
+                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unexpected action result!");
+                break;
+        }
+    }
+
+    /**
+     * Processes a request from a webapp to perform an action on a service or
+     * plugin.
+     *
+     * @param request the webapp request object.
+     * @param response the webapp response object.
+     * @throws IOException if there was an error while attempting to perform the
+     * requested action.
+     * @return an int value that represents theresult of the operation performed
+     * (see Services.RES_* for values/name pairs).
+     */
+    public int processWebappRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        // try to perform the action
+        int result = performAction(request);
+
+        // check the result and repond accordingly
+        switch (result) {
+            case RES_OK:
+                response.setStatus(HttpServletResponse.SC_OK);
+                break;
+
+            case RES_NO_ACTION:
+                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                break;
+
+            case RES_INVALID_ACTION:
+                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                break;
+
+            case RES_NO_SERVICE_NAME:
+                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                break;
+
+            case RES_INVALID_SERVICE_NAME:
+                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                break;
+
+            case RES_WARNING:
+            default:
+                response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                break;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the form element to perform some action
+     * an a plugin name by the brokerURL.
+     *
+     * @param brokerURL the URL where the form will post its data.
+     * @param action the action to take.
+     * @param name the name of the service or plugin where the action will be
+     * performed.
+     * @return an HTML String containing the form element to perform some action
+     * an a plugin name by the brokerURL.
+     */
+    private String getHTMLActionForm(String brokerURL, String action, String name) {
+        String result = "<form action=\"" + brokerURL + "\" method=\"get\"><input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + action.toLowerCase() + "\" /><input type=\"hidden\" name=\"" + PARAM_SERVICE + "\" value=\"" + name + "\" />";
+
+        String buttonStyle = "btn";
+        if (action.equalsIgnoreCase("start")) {
+            buttonStyle += " btn-success";
+        }
+        if (action.equalsIgnoreCase("stop")) {
+            buttonStyle += " btn-danger";
+        }
+
+        result += "<input type=\"submit\" class=\"" + buttonStyle + "\" value=\"" + action + "\" />";
+
+        // add a little warning for stopping the web server, making it unable to be used remotely again
+		/*if (name.equalsIgnoreCase(webServerName))
+         {
+         result += "<div class=\"warning\"><span class=\"notice\">!</span></div>";
+         }*/
+
+        result += "</form>";
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the form element to change the start on
+     * init flag of a plugin name by the brokerURL.
+     *
+     * @param brokerURL the URL where the form will post its data.
+     * @param name the name of the service or plugin where the action will be
+     * performed.
+     * @param startInitially if the plugin or service is currently set to start
+     * initially or not.
+     * @param canBeDisabled if this plugin or service can be disabled.
+     * @return an HTML String containing the form element to change the start on
+     * init flag of a plugin name by the brokerURL.
+     */
+    private String getHTMLStartOnInitForm(String brokerURL, String name, boolean startInitially, boolean canBeDisabled) {
+        String result = "<form action=\"" + brokerURL + "\" method=\"get\"><input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_INIT_START + "\" /><input type=\"hidden\" name=\"" + PARAM_SERVICE + "\" value=\"" + name + "\" />";
+
+        result += "<label for=\"" + PARAM_INIT_START + "-" + Utils.getHTMLElementIDFromString(name) + "\" class=\"checkbox inline\">";
+        result += "<input type=\"checkbox\" id=\"" + PARAM_INIT_START + "-" + Utils.getHTMLElementIDFromString(name) + "\" name=\"" + PARAM_INIT_START + "\" " + (startInitially ? "checked=\"checked\"" : "") + " onclick=\"this.parent.submit();\" " + (canBeDisabled ? "" : "disabled=\"disabled\"") + " /> Auto Start";
+        result += "</label>";
+        result += "<input type=\"submit\" hidden=\"hidden\" />";
+
+        // add a little warning for disabling the web server, making it unable to be used remotely again
+		/*if (name.equalsIgnoreCase(webServerName))
+         {
+         result += "<div class=\"warning\"><span class=\"notice\">!</span></div>";
+         }*/
+
+        result += "</form>";
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the form element to change the port
+     * number of a plugin name by the brokerURL.
+     *
+     * @param brokerURL the URL where the form will post its data.
+     * @param name the name of the service or plugin where the action will be
+     * performed.
+     * @param port the current plugin or service port number.
+     * @return an HTML String containing the form element to change the port
+     * number of a plugin name by the brokerURL.
+     */
+    private String getHTMLPortForm(String brokerURL, String name, int port) {
+        String result = "<form action=\"" + brokerURL + "\" method=\"get\"><input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_SET_PORT + "\" /><input type=\"hidden\" name=\"" + PARAM_SERVICE + "\" value=\"" + name + "\" />";
+
+        result += "<label for=\"" + PARAM_PORT + "-" + Utils.getHTMLElementIDFromString(name) + "\">";
+        result += "Port: " + "<input id=\"" + PARAM_PORT + "-" + Utils.getHTMLElementIDFromString(name) + "\" type=\"number\" name=\"" + PARAM_PORT + "\" min=\"0\" max=\"65535\" maxlength=\"5\" size=\"5\" value=\"" + port + "\" class=\"input-small\" style=\"margin-right: 10px;\"/>";
+        result += "<input type=\"submit\" class=\"btn\" value=\"Set Port\" class=\"btn\" />";
+        result += "</label>";
+
+        // add a little warning for stopping the web server, making it unable to be used remotely again
+		/*if (name.equalsIgnoreCase(webServerName))
+         {
+         result += "<div class=\"warning\"><span class=\"notice\">!</span></div>";
+         }*/
+
+        result += "</form>";
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the form element to see and modify the
+     * advanced/internal options of a plugin or service name by the brokerURL.
+     *
+     * @param brokerURL the URL where the form will post its data.
+     * @param name the name of the service or plugin where the action will be
+     * performed.
+     * @return an HTML String containing the form element to see and modify the
+     * advanced/internal options of a plugin or service name by the brokerURL.
+     */
+    @Deprecated
+    private String getHTMLAdvancedOptionForm(String brokerURL, String name) {
+        String result = "<form action=\"" + brokerURL + "\" method=\"get\"><input type=\"hidden\" name=\"" + PARAM_SERVICE + "\" value=\"" + name + "\" />";
+
+        result += "<input type=\"submit\" class=\"btn\" value=\"Advanced Options\" class=\"btn btn-info\" />";
+
+        result += "</form>";
+
+        return result;
+    }
+
+    /**
+     * Returns a String containing the HTML code for a row to the HTML service
+     * management table, based o the parameters passed to it.
+     *
+     * @param isRunning if the target service is currently running.
+     * @param brokerURL the url of the service broker.
+     * @param name the name of the target service.
+     * @param canBeDisabled if the plugins or service can be disabled from
+     * starting/stoping.
+     * @param startInitially if the plugin or service is currently set to be
+     * start on server initialization.
+     * @param hasPort if the plugin or service has a port number that can be
+     * changed.
+     * @param port the current port number of the plugin or service.
+     * @param hasAdvancedOptions if the pugin or service has advanced (internal)
+     * options.
+     * @param advancedOptionsManagerURL the URL of the pugin or service advanced
+     * options manager.
+     * @return a String containing the HTML code for a row to the HTML service
+     * management table, based o the parameters passed to it.
+     */
+    @Deprecated
+    private String getHTMLServiceManagementTableRow(boolean isRunning, String brokerURL, String name, boolean canBeStopped, boolean canBeDisabled, boolean startInitially, boolean hasPort, int port, boolean hasAdvancedOptions, String advancedOptionsManagerURL) {
+        String result = "<tr " + (name.equalsIgnoreCase(webServerName) ? "class=\"warning\"" : "") + ">"; // add a little warning for stopping the web server, making it unable to be used remotely again
+
+        result += "<td>" + escapeHtml4(name) + "</td>";
+        if (isRunning) {
+            result += "<td class=\"running\">Running</td>";
+            if (canBeStopped) {
+                result += "<td>" + getHTMLActionForm(brokerURL, "Stop", name) + "</td>";
+            } else {
+                result += "<td></td>";
+            }
+        } else {
+            result += "<td class=\"stopped\">Stopped</td>";
+            if (canBeStopped) {
+                result += "<td>" + getHTMLActionForm(brokerURL, "Start", name) + "</td>";
+            } else {
+                result += "<td>" + "<div class=\"error\"></div>" + getHTMLActionForm(brokerURL, "Start", name) + "</td>"; // add a little error notification, so that the admin can see that the plugin failed to start
+            }
+        }
+        result += "<td>" + getHTMLStartOnInitForm(brokerURL, name, startInitially, canBeDisabled) + "</td>";
+        if (hasPort) {
+            result += "<td>" + getHTMLPortForm(brokerURL, name, port) + "</td>";
+        } else {
+            result += "<td></td>";
+        }
+        if (hasAdvancedOptions) {
+            result += "<td>" + getHTMLAdvancedOptionForm(advancedOptionsManagerURL, name) + "</td>";
+        } else {
+            result += "<td></td>";
+        }
+
+        result += "</tr>";
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the list of all plugins and services
+     * available, their status and action that can be taken.
+     *
+     * @param brokerURL the URL of the service manager page (where the form will
+     * post data to).
+     * @param advancedOptionsManagerURL the URL of the plugin/service
+     * advanced/internal options manager.
+     * @param id the ID of this HTML element, can be null if not needed.
+     * @return an HTML String containing the list of all plugins and services
+     * available, their status and action that can be taken.
+     */
+    @Deprecated
+    public String getHTMLServiceManagementTable(String brokerURL, String advancedOptionsManagerURL, String id) {
+        String result = "";
+        if ((id == null) || id.trim().isEmpty()) {
+            result += "<table class=\"table table-striped\">";
+        } else {
+            result += "<table id=\"" + id + "\" class=\"table table-striped\">";
+        }
+        result += "<thead>";
+        result += "<tr>";
+        result += "<th>Name</th>";
+        result += "<th>Status</th>";
+        result += "<th>Actions</th>";
+        result += "<th>Start on Init</th>";
+        result += "<th>Options</th>";
+        result += "<th>Advanced Options</th>";
+        result += "</tr>";
+        result += "</thead>";
+        result += "<tbody>";
+
+        // list all the plugins
+        //TODO: DELETED
+        /*for (String plug : plgs.getPluginsNames()) {
+            result += getHTMLServiceManagementTableRow(plgs.isPluginRunning(plug), brokerURL, plug, true, true, cfgs.getAutoStartPlugin(plug), false, 0, plgs.hasAdvancedSettings(plug), advancedOptionsManagerURL);
+        }*/
+        // list the storage service
+        result += getHTMLServiceManagementTableRow(svcs.storageIsRunning(), brokerURL, storageName, true, true, storageStart(), true, storagePort(), false, /*advancedOptionsManagerURL*/ null);
+        // list the query retrieve service
+        result += getHTMLServiceManagementTableRow(svcs.queryRetrieveIsRunning(), brokerURL, queryRetrieveName, true, true, queryRetrieveStart(), true, queryRetrievePort(), true, advancedOptionsManagerURL);
+        // list the web services
+        //result += getHTMLServiceManagementTableRow(false, brokerURL, webServicesName, false, false, false, true, webServicesPort(), false, null);
+        // list the web server
+        result += getHTMLServiceManagementTableRow(svcs.webServerIsRunning(), brokerURL, webServerName, true, true, webServerStart(), true, webServerPort(), false, null);
+        // list the RMI service
+        result += getHTMLServiceManagementTableRow(true, brokerURL, remoteGUIName, false, false, true, true, remoteGUIPort(), true, advancedOptionsManagerURL); // FIXME actually get if the RMI is running or not
+
+        result += "</tbody>";
+        result += "</table>";
+
+        return result;
+    }
+
+    /**
+     * Returns an HTML String containing the list of all plugins and services
+     * available, their status and action that can be taken.
+     *
+     * @param brokerURL the URL of the service manager page (where the form will
+     * post data to).
+     * @param advancedOptionsManagerURL the URL of the plugin/service
+     * advanced/internal options manager.
+     * @return an HTML String containing the list of all plugins and services
+     * available, their status and action that can be taken.
+     */
+    @Deprecated
+    public String getHTMLServiceManagementTable(String brokerURL, String advancedOptionsManagerURL) {
+        return getHTMLServiceManagementTable(brokerURL, advancedOptionsManagerURL, null);
+    }
+
+    /**
+     * Return if the Storage service is started initially.
+     *
+     * @return if the Storage service is started initially.
+     */
+    public boolean storageStart() {
+        return cfgs.isStorage();
+    }
+
+    /**
+     * Return if the QueryRetrieve service is started initially.
+     *
+     * @return if the QueryRetrieve service is started initially.
+     */
+    public boolean queryRetrieveStart() {
+        return cfgs.isQueryRetrive();
+    }
+
+    /**
+     * Return if the WebServices service is started initially.
+     *
+     * @return if the WebServices service is started initially.
+     */
+    public boolean webServicesStart() {
+        return cfgs.getWeb().isWebServices();
+    }
+
+    /**
+     * Return if the WebServer service is started initially.
+     *
+     * @return if the WebServer service is started initially.
+     */
+    public boolean webServerStart() {
+        return cfgs.getWeb().isWebServer();
+    }
+
+    /**
+     * Sets if the Storage service is started initially.
+     *
+     * @param start if the Storage service is started initially.
+     */
+    public void setStorageStart(boolean start) {
+        cfgs.setStorage(start);
+    }
+
+    /**
+     * Sets if the QueryRetrieve service is started initially.
+     *
+     * @param start if the QueryRetrieve service is started initially.
+     */
+    public void setQueryRetrieveStart(boolean start) {
+        cfgs.setQueryRetrive(start);
+    }
+
+    /**
+     * Sets if the WebServices service is started initially.
+     *
+     * @param start if the WebServices service is started initially.
+     */
+    public void setWebServicesStart(boolean start) {
+        cfgs.getWeb().setWebServices(start);
+    }
+
+    /**
+     * Sets if the WebServer service is started initially.
+     *
+     * @param start if the WebServer service is started initially.
+     */
+    public void setWebServerStart(boolean start) {
+        cfgs.getWeb().setWebServer(start);
+    }
+
+    /**
+     * Returns the Storage service port.
+     *
+     * @return the Storage service port.
+     */
+    public int storagePort() {
+        return cfgs.getStoragePort();
+    }
+
+    /**
+     * Returns the QueryRetrieve service port.
+     *
+     * @return the QueryRetrieve service port.
+     */
+    public int queryRetrievePort() {
+        return cfgs.getWlsPort();
+    }
+
+    /**
+     * Returns the WebServices service port.
+     *
+     * @return the WebServices service port.
+     */
+    public int webServicesPort() {
+        return cfgs.getWeb().getServicePort();
+    }
+
+    /**
+     * Returns the WebServer service port.
+     *
+     * @return the WebServer service port.
+     */
+    public int webServerPort() {
+        return cfgs.getWeb().getServerPort();
+    }
+
+    /**
+     * Returns the RemoteGUI service port.
+     *
+     * @return the RemoteGUI service port.
+     */
+    public int remoteGUIPort() {
+        return cfgs.getRemoteGUIPort();
+    }
+
+    /**
+     * Returns the RemoteGUI service external IP.
+     *
+     * @return the RemoteGUI service external IP.
+     */
+    public String remoteGUIExtIP() {
+        return cfgs.getRGUIExternalIP();
+    }
+
+    /**
+     * Sets the Storage service port.
+     *
+     * @param port the Storage service port.
+     */
+    public void setStoragePort(int port) {
+        cfgs.setStoragePort(port);
+    }
+
+    /**
+     * Sets the QueryRetrieve service port.
+     *
+     * @param port the QueryRetrieve service port.
+     */
+    public void setQueryRetrievePort(int port) {
+        cfgs.setWlsPort(port);
+    }
+
+    /**
+     * Sets the WebServices service port.
+     *
+     * @param port the WebServices service port.
+     */
+    public void setWebServicesPort(int port) {
+        cfgs.getWeb().setServicePort(port);
+    }
+
+    /**
+     * Sets the WebServer service port.
+     *
+     * @param port the WebServer service port.
+     */
+    public void setWebServerPort(int port) {
+        cfgs.getWeb().setServerPort(port);
+    }
+
+    /**
+     * Sets the RemoteGUI service port.
+     *
+     * @param port the RemoteGUI service port.
+     */
+    public void setRemoteGUIPort(int port) {
+        cfgs.setRemoteGUIPort(port);
+    }
+
+    /**
+     * Sets the RemoteGUI service external IP.
+     *
+     * @param extIP the RemoteGUI service external IP.
+     */
+    public void setRemoteGUIExtIP(String extIP) {
+        cfgs.setRGUIExternalIP(extIP);
+    }
+
+    /**
+     * Saves the settings for use between server inits.
+     */
+    public void saveSettings() {
+        
+        xmlSupport.printXML();
+    }
+
+    /**
+     * For a request, returns the name of the service/plugin required.
+     *
+     * @param request the servlet request object.
+     * @return the name of the service/plugin required.
+     * @throws IOException
+     */
+    public String getRequestServiceName(HttpServletRequest request) throws IOException {
+        // set proper encoding on the request
+        request.setCharacterEncoding("UTF-8");
+
+        // get the name of the service/plugin
+        return request.getParameter(PARAM_SERVICE);
+    }
+
+    public String getHTMLSettingHelp(String fieldTitle, String help) {
+        String result = "";
+
+        // make sure that there is a valid help notice
+        if (help == null) {
+            return result;
+        }
+        help = help.trim();
+        if (help.isEmpty()) {
+            return result;
+        }
+
+        // replace the "\n" (#13/#10) with "\\n" so that JS can interpret that correctly instead of ending up with a new line on the document
+        //help = help.replaceAll("\n", "\\\\n");
+        // also the "\t" ones
+        //help = help.replaceAll("\t", "\\\\t");
+
+        // add a button that will show the help (button because of touch interfaces, instead of popup for desktop)
+        System.out.println("HELP: "+help);
+        String msg = escapeHtml4(help.replaceAll("\n", "<br>"));
+        result += buildInfoButton(fieldTitle, msg);
+        		System.out.println("MSG: "+msg);
+        return result;
+    }
+    
+   private String buildInfoButton(String title, String msg){
+    	StringBuilder builder = new StringBuilder();
+    	
+    	builder.append("<a ");
+    	//builder.append(id);
+    	builder.append(" data-original-title=\"");
+    	builder.append(title);
+    	builder.append("\" href=\"#\" class=\"btn btn-mini btn-info\" data-toggle=\"popover\" data-html=\"true\" data-content=\"");
+    	builder.append(msg);
+    	builder.append("\" onclick=\"return false;\">Info</a>\n");
+    	
+    	return builder.toString();
+    }
+    
+
+    /**
+     * Returns a row for the advanced settings form.
+     *
+     * @param name the name of the setting.
+     * @param value the type/value of the setting.
+     * @param help s String containing a help notice for this setting, can be
+     * null if not needed.
+     * @return a String containing a HTML code to a row for the advanced
+     * settings form.
+     */
+    public String getHTMLAdvancedSettingsFormRow(String name, Object value, String help) {
+    	
+        String result = "";
+
+        String id = Utils.getHTMLElementIDFromString(name);
+
+        result += "<tr>";
+
+        result += "<td><label for=\"" + id + "\">" + escapeHtml4(name) + ":</label></td>";
+        result += "<td>" + Utils.getHTMLInputFromType(id, value) + getHTMLSettingHelp(escapeHtml4(name) , help) + "</td>"; // TODO add a button with help, like in the desktop application [getHelpForParam(pluginName, paramName) != null]
+
+        result += "</tr>";
+
+        return result;
+    }
+
+    /**
+     * Based on the request, returns a String containing a form with all the
+     * settings inputs boxes. These boxes are rendered/specified in accordance
+     * with the each setting value type reported by the plugin/service.
+     *
+     * @param request the servlet request object.
+     * @param brokerURL the URL of the broker that will apply the settings after
+     * receiving this forms post.
+     * @param elementID the ID of this HTML form, can be null.
+     * @return a String containing the HTML structure for the form with all the
+     * plugin advanced setting.
+     */
+    public String getHTMLServiceAdvancedSettingsForm(HttpServletRequest request, String brokerURL, String elementID) throws IOException {
+        String result = "";
+
+        String name = getRequestServiceName(request);
+
+        // test if this is a embeded service and has advanced settings
+        boolean isStorage = storageName.equalsIgnoreCase(name);
+        boolean isQueryRetrieve = queryRetrieveName.equalsIgnoreCase(name);
+        boolean isRemoteGUI = remoteGUIName.equalsIgnoreCase(name);
+        boolean isEmbededService = isStorage || isQueryRetrieve || isRemoteGUI;
+
+        // if it's not a embeded service
+        if (!isEmbededService) {
+            // test if it's a plugin and has advanced settings
+            if (!plgs.hasAdvancedSettings(name)) {
+                result += "<h3>The required plugin/service is either invalid or has no advanced settings!</h3>";
+                return result;
+            }
+        }
+
+        if ((elementID == null) || elementID.trim().isEmpty()) {
+            result += "<form ";
+        } else {
+            result += "<form id=\"" + elementID + "\" ";
+        }
+        result += "action=\"" + brokerURL + "\" method=\"get\">";
+
+        result += "<input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_SET_ADVANCED_SETTINGS + "\" />";
+        result += "<input type=\"hidden\" name=\"" + PARAM_SERVICE + "\" value=\"" + escapeHtml4(name) + "\" />";
+
+        result += "<table class=\"table table-hover\"><tbody>";
+
+        HashMap<String, Object> settings = null;
+        HashMap<String, String> settingsHelp = null;
+        if (!isEmbededService) // if it's a plugin
+        {
+        	//TODO: DELETED
+            //settings = plgs.getAdvancedSettings(name);
+            settingsHelp = plgs.getAdvancedSettingsHelp(name);
+        } else {
+            if (isStorage) {
+                settings = cfgs.getStorageSettings();
+                settingsHelp = cfgs.getStorageSettingsHelp();
+            } else if (isQueryRetrieve) {
+                settings = cfgs.getQueryRetrieveSettings();
+                settingsHelp = cfgs.getQueryRetrieveSettingsHelp();
+            } else // Remote GUI
+            {
+                settings = cfgs.getRGUISettings();
+                settingsHelp = cfgs.getRGUISettingsHelp();
+            }
+        }
+        // just to avoid any unwanted exceptions, in case a plugin misbehaves
+        if (settings == null) {
+            settings = new HashMap<String, Object>();
+        }
+        if (settingsHelp == null) {
+            settingsHelp = new HashMap<String, String>();
+        }
+
+        // create a table row for each setting (includes name, value/type and help, if available)
+        for (Map.Entry<String, Object> setting : settings.entrySet()) {
+            String key = setting.getKey();
+            Object value = setting.getValue();
+            String help = settingsHelp.get(key);
+
+            result += getHTMLAdvancedSettingsFormRow(key, value, help);
+        }
+
+        result += "</tbody></table><br />";
+
+        result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
+        result += "</form>";
+
+        return result;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExamTimeResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExamTimeResource.java
new file mode 100644
index 0000000..b80a261
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExamTimeResource.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.io.File;
+import org.restlet.data.Disposition;
+import org.restlet.data.MediaType;
+import org.restlet.representation.FileRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.server.web.rest.elements.ExamTimeCore;
+
+/**
+ *
+ * @author samuelcampos
+ */
+public class ExamTimeResource extends ServerResource {
+
+    @Get
+    public Representation represent() {
+        String action = getRequest().getResourceRef().getQueryAsForm().getValues("action");
+
+        if (action == null) {
+            return new StringRepresentation("", MediaType.TEXT_ALL);
+        }
+
+        ExamTimeCore examTime = ExamTimeCore.getInstance();
+
+
+        if (action.equalsIgnoreCase("getState")) {
+            ExamTimeCore.ExamTimeState state = examTime.getState();
+
+            return new StringRepresentation(state.name(), MediaType.TEXT_ALL);
+        }
+        
+        if (action.equalsIgnoreCase("percentage")) {
+            return new StringRepresentation(examTime.getPercentage() + "", MediaType.TEXT_ALL);
+        }
+
+        if (action.equalsIgnoreCase("startCalc")) {
+            examTime.startThread();
+
+            return new StringRepresentation("OK", MediaType.TEXT_ALL);
+        }
+
+        if (action.equalsIgnoreCase("stopCalc")) {
+            examTime.stopThread();
+
+            return new StringRepresentation("OK", MediaType.TEXT_ALL);
+        }
+
+        if (action.equalsIgnoreCase("download")) {
+            File file = examTime.getFile();
+            
+            if(file == null){
+                return new StringRepresentation("ERROR", MediaType.TEXT_ALL);
+            }
+            
+            FileRepresentation FRepre = new FileRepresentation(file, MediaType.TEXT_CSV);
+            FRepre.getDisposition().setType(Disposition.TYPE_ATTACHMENT);
+            FRepre.getDisposition().setFilename(file.getName());
+
+            return FRepre;
+        }
+
+
+        return new StringRepresentation("UNKNOW_ACTION", MediaType.TEXT_ALL);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExtResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExtResource.java
new file mode 100644
index 0000000..73cbff1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ExtResource.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
+import org.restlet.resource.ResourceException;
+import org.restlet.resource.ServerResource;
+
+/**
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class ExtResource extends ServerResource {
+    @Override
+    protected Representation doHandle() {
+        throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ForceIndexing.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ForceIndexing.java
new file mode 100644
index 0000000..08da6f3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/ForceIndexing.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+public class ForceIndexing extends ServerResource{
+    
+	private static final Logger log = LoggerFactory.getLogger(ForceIndexing.class);	
+	
+    @Get
+    public Representation represent(){
+    	
+        Form queryForm = getRequest().getResourceRef().getQueryAsForm();
+        //System.out.println("Fetching Data");
+        String[] uris = queryForm.getValuesArray("uri");
+        String pluginName = queryForm.getValues("plugin");
+        
+        PluginController pc = PluginController.getInstance();
+        //System.out.println("Generating Tasks");
+        List<Task<Report>> reports  = new ArrayList<>(uris.length);
+        for(String uriString : uris) {
+            URI u = null;
+            try {
+                u = new URI(uriString.replaceAll(" ","%20"));
+            } catch (URISyntaxException ex) {
+            	log.error("Could not create URI", ex);
+                ex.printStackTrace();
+            } 
+            if(u != null){
+            	log.info("Sent Index Request: {}, {}",pluginName, u.toString());
+            	if(pluginName == null)
+            		reports.addAll(pc.index(u));
+            	else
+            		reports.addAll(pc.index(pluginName,u));
+            }
+        }
+        
+        //System.out.println("Waiting for Results");
+        List<Report> done = new ArrayList<>(reports.size());
+        StringBuilder builder = new StringBuilder();
+        for(Task<Report> t : reports){
+            try {
+            	Report r = t.get();
+                done.add(r);
+                builder.append(r).append("\n");
+            }catch(InterruptedException | ExecutionException ex){
+            	log.error("UNKNOW ERROR", ex);
+            	ex.printStackTrace();
+            }
+        }
+        //System.out.println("Exporting Results");
+        
+        log.info("Finished forced indexing procedure: {}", reports.size());
+        
+        return new StringRepresentation(builder.toString(), MediaType.TEXT_PLAIN);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestCountQueryResults.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestCountQueryResults.java
new file mode 100755
index 0000000..4833ff4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestCountQueryResults.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import org.apache.commons.lang.NotImplementedException;
+import org.restlet.data.MediaType;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class RestCountQueryResults extends ServerResource{ 
+    
+    @Get
+    public Representation represent(){
+        
+        String search = getRequest().getResourceRef().getQueryAsForm().getValues("q");
+        String advSearch = getRequest().getResourceRef().getQueryAsForm().getValues("advq");
+
+        if(advSearch == null){
+            //prepares query
+            if(search == null) search="";
+            else if(search.equals("null")) search = "";
+
+            if (search.equals(""))
+                search = "*:*";
+            else{
+                QueryExpressionBuilder q = new QueryExpressionBuilder(search);
+                search = q.getQueryString();
+            }
+        }
+        else{
+            search = advSearch;
+        }
+
+        
+        throw new NotImplementedException("Deprecated: RMI", null);
+        
+        //return new StringRepresentation("" + nResults, MediaType.TEXT_PLAIN);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDcmImageResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDcmImageResource.java
new file mode 100644
index 0000000..5a180e1
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDcmImageResource.java
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.Iterator;
+import org.slf4j.LoggerFactory;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam;
+import org.restlet.data.MediaType;
+import org.restlet.representation.ByteArrayRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.plugins.PluginController;
+
+/**
+ *
+ * @author psytek
+ *
+ * WARNING: lame workaround implementation to get some images
+ * lets not even discuss security
+ *
+ */
+public class RestDcmImageResource extends ServerResource {
+
+    private PluginController core;
+
+    public RestDcmImageResource() {
+        this.core = PluginController.getInstance();
+    }
+    
+    @Get("image/jpeg")
+    public void getJPEG() {
+        BufferedImage dicomImage=null;
+        String imgPath = getRequest().getResourceRef().getQueryAsForm().getValues("path");
+        if (imgPath == null) {return;}
+        
+        int indexExt = imgPath.lastIndexOf('.');
+        if(indexExt == -1) imgPath += ".dcm"; //a lot of dicom files have no extension
+        
+        String extension = imgPath.substring(indexExt);
+        switch(extension.toLowerCase()){
+            case ".jpg":    //these are not indexed
+            case ".png":
+            case ".gif":
+            case ".bmp":
+            case ".tiff":
+            case ".jpeg":{
+                File file = new File(imgPath);
+
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                try {
+                    BufferedImage img = ImageIO.read(file);
+                    ImageIO.write(img, "jpg", baos);
+                    baos.flush();
+                    ByteArrayRepresentation bar = new ByteArrayRepresentation(baos.toByteArray(), MediaType.IMAGE_JPEG);
+                    getResponse().setEntity(bar);
+                    baos.close();
+                }
+                catch (IOException e) {
+                    LoggerFactory.getLogger(RestDcmImageResource.class).error(e.getMessage(), e);
+                }
+                break;
+            }
+            case ".dicom":  //these are
+            case ".dcm":{
+                File file = new File(imgPath);
+                //todo:if not file...
+
+                Iterator<ImageReader> iterator =ImageIO.getImageReadersByFormatName("DICOM");
+                while (iterator.hasNext()) {
+                    ImageReader imageReader = (ImageReader) iterator.next();
+                    DicomImageReadParam dicomImageReadParam = (DicomImageReadParam) imageReader.getDefaultReadParam();
+                    try {
+                        ImageInputStream iis = ImageIO.createImageInputStream(file);
+                        imageReader.setInput(iis,false);
+                        dicomImage = imageReader.read(0, dicomImageReadParam);
+                        iis.close();
+                        if(dicomImage == null){
+                            System.err.println("Could not read image!!");
+                        }
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    try{
+                        ImageIO.write(dicomImage, "jpg", baos);
+                        baos.flush();
+                        ByteArrayRepresentation bar = new ByteArrayRepresentation(baos.toByteArray(), MediaType.IMAGE_JPEG);
+                        getResponse().setEntity(bar);
+                        baos.close();
+                    }
+                    catch(IOException e){
+                        LoggerFactory.getLogger(RestDcmImageResource.class).error(e.getMessage(), e);
+                        return;
+                    }
+                }
+                break;
+            }
+        }
+    }     
+}
+
+    
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDimResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDimResource.java
new file mode 100755
index 0000000..6bf71fb
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDimResource.java
@@ -0,0 +1,235 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang3.StringUtils;
+import org.restlet.data.Form;
+import org.restlet.data.MediaType;
+import org.restlet.data.Status;
+import org.restlet.representation.EmptyRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.core.dim.DIMGeneric;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author fmvalente
+ */
+
+
+//TODO:add type to file search
+public class RestDimResource extends ServerResource{
+    
+	private static final Logger log = LoggerFactory.getLogger(RestDimResource.class);
+	
+    @Get
+    public Representation represent(){
+    	
+        Form queryForm = getRequest().getResourceRef().getQueryAsForm();
+    
+        String search = queryForm.getValues("q");
+        String advSearch = queryForm.getValues("advq");
+        
+        if(StringUtils.isNotEmpty(search)){
+            QueryExpressionBuilder q = new QueryExpressionBuilder(search);
+            search = q.getQueryString();
+        }else if (StringUtils.isNotEmpty(advSearch)) {
+			search = advSearch;
+		}else{
+			//SEND ERROR NO QUERY DEFINED
+			setStatus(new Status(401), "No Query String Provided: Please provide a query either by ?advq, for advanced searches, or ?q for free text");
+			return new EmptyRepresentation();
+		}
+        
+        String type = queryForm.getValues("type");
+        boolean dim = true;
+        if(StringUtils.isNotEmpty(type)){
+        	if(type.equalsIgnoreCase("DIM")){
+        		dim = true;
+        	}else if (type.equalsIgnoreCase("RAW")) {
+				dim = false;
+			}else{
+				//SEND ERROR!! WRONG RETURN TYPE
+				setStatus(new Status(402), "Wrong return type: Supported types, dim (default), raw.");
+				
+				return new EmptyRepresentation();
+			}
+        }
+        
+        List<String> knownProviders = new ArrayList<String>();
+        String[] providers = queryForm.getValuesArray("provider");
+        List<String> activeProviders = PluginController.getInstance().getQueryProvidersName(true);
+        boolean queryAll = providers.length == 0;
+    	for(String p : providers){
+        	if(p.equalsIgnoreCase("all")){
+        		queryAll = true;
+    			break;
+        	}else if(activeProviders.contains(p)){
+        		knownProviders.add(p);
+        	}
+        }
+        activeProviders = null;
+                
+        String[] extraFieldList = queryForm.getValuesArray("field");
+        HashMap<String, String> extraFields = new HashMap<String, String>();
+        //attaches the required extrafields
+        if(extraFieldList.length == 0 || dim){
+            extraFields.put("PatientName", "PatientName");
+            extraFields.put("PatientID", "PatientID");
+            extraFields.put("Modality", "Modality");
+            extraFields.put("StudyDate", "StudyDate");
+            extraFields.put("SeriesInstanceUID", "SeriesInstanceUID");
+            extraFields.put("StudyID", "StudyID");
+            extraFields.put("StudyInstanceUID", "StudyInstanceUID");
+            extraFields.put("Thumbnail", "Thumbnail");
+            extraFields.put("SOPInstanceUID", "SOPInstanceUID");
+        }else{
+            Map<String, String> availableTags = new HashMap<String, String>();
+            for(String tag : DictionaryAccess.getInstance().getTagList().keySet()){
+                availableTags.put(tag.toLowerCase(), tag);
+            }            
+            for(String f : extraFieldList){
+                if(f.equalsIgnoreCase("all")){
+                    for(String k : availableTags.values()){
+                        extraFields.put(k, k);
+                    }
+                    break;
+                }
+                if(availableTags.containsKey(f)){
+                    extraFields.put(availableTags.get(f), availableTags.get(f));
+                }
+            }
+        }
+                
+        //System.err.println("ADVSEARCH: "+advSearch);
+        //System.err.println("FINAL SEARCH QUERY: "+search);
+
+        long startTime = System.currentTimeMillis();
+        MyHolder holder = new MyHolder();
+        if(queryAll)
+        	PluginController.getInstance().queryAll(holder, search, extraFields);
+        else
+        	PluginController.getInstance().query(holder, knownProviders, search, extraFields);
+        
+    	ArrayList<SearchResult> resultsArr = new ArrayList<SearchResult>();
+        
+		try {
+			Iterable<SearchResult> results = holder.get();
+		
+			for(SearchResult r : results)
+	        	resultsArr.add(r);
+	        
+	        results = null;
+	        
+		} catch (InterruptedException | ExecutionException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		startTime = System.currentTimeMillis() - startTime;
+		
+		String ret = "";
+		MediaType mtype = null;
+		if(dim){
+			ret = processDIMResults(resultsArr);
+			mtype = MediaType.APPLICATION_XML;			
+		}else{
+			ret = processJSON(resultsArr, startTime);
+			mtype = MediaType.APPLICATION_JSON;
+		}
+		
+		if(StringUtils.isEmpty(ret) && !resultsArr.isEmpty()){
+			//RAISE ERROR
+			setStatus(new Status(400), "Error parsing results data:");
+			return new EmptyRepresentation();
+		}
+        
+        //constructs our xml data struct
+        return new StringRepresentation(ret, mtype);
+    }
+    
+    private static String processDIMResults(Collection<SearchResult> results){
+    	DIMGeneric dim = null;
+        try{
+            dim = new DIMGeneric(results);
+            return dim.getXML();
+        }
+        catch (Exception ex) {
+//            LoggerFactory.getLogger(RestDimResource.class).error(ex.getMessage(), ex);
+        	ex.printStackTrace();
+        }
+        //and returns an xml version of our dim search
+        return null;
+
+    }
+    
+    private static String processJSON(Collection<SearchResult> results, long elapsedTime){
+    	JSONObject resp = new JSONObject();
+    	for(SearchResult r : results){
+    		JSONObject rj = new JSONObject();
+    		rj.put("uri", r.getURI().toString());
+    		
+    		JSONObject fields = new JSONObject();
+    		fields.accumulateAll(r.getExtraData());
+    		
+    		rj.put("fields", fields);
+    		
+    		resp.accumulate("results", rj);
+    	}
+    	resp.put("numResults", results.size());
+    	resp.put("elapsedTime", elapsedTime);
+    	
+    	return resp.toString();
+    }
+    
+    private static class MyHolder extends JointQueryTask{
+
+		@Override
+		public void onCompletion() {
+			// TODO Auto-generated method stub
+			
+		}
+
+		@Override
+		public void onReceive(Task<Iterable<SearchResult>> e) {
+			// TODO Auto-generated method stub
+			
+		}
+    	
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDumpResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDumpResource.java
new file mode 100755
index 0000000..c483c97
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestDumpResource.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.LoggerFactory;
+import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml3;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author fmvalente
+ */
+
+
+//TODO:add type to file search
+public class RestDumpResource extends ServerResource{
+        
+    @Get
+    public String represent(){
+        
+        
+        
+        String SOPInstanceUID = getRequest().getResourceRef().getQueryAsForm().getValues("uid");
+        if(SOPInstanceUID == null) return null;
+        
+        DictionaryAccess da = DictionaryAccess.getInstance() ; 
+        
+        String query = "SOPInstanceUID:"+SOPInstanceUID;
+        
+        
+        HashMap<String, String> extraFields = new HashMap<String, String>();
+        
+        for (String s : da.getTagList().keySet()) {
+                extraFields.put(s, s);
+        }
+
+        JointQueryTask holder = new JointQueryTask() {
+
+                @Override
+                public void onReceive(Task<Iterable<SearchResult>> e) {
+                    try {
+                        // TODO Auto-generated method stub
+                    System.out.println("onReceive");
+                    for (SearchResult r : e.get())
+                    {
+                        System.out.println(r.getURI());
+                    }
+                    } catch (InterruptedException ex) {
+                        LoggerFactory.getLogger(RestDumpResource.class).error(ex.getMessage(), ex);
+                    } catch (ExecutionException ex) {
+                        LoggerFactory.getLogger(RestDumpResource.class).error(ex.getMessage(), ex);
+                    }
+
+                }
+
+                @Override
+                public void onCompletion() {
+                        // TODO Auto-generated method stub
+                    System.out.println("onComplete");
+
+                }
+        };
+
+        //performs the search
+        Iterable<SearchResult> queryResultList = null;
+        try {
+            System.out.println("Query: + " + query);
+            queryResultList = PluginController.getInstance().queryAll(holder, query, extraFields).get();
+            Thread.sleep(1000);
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(RestDumpResource.class).error(ex.getMessage(), ex);
+        } catch (ExecutionException ex) {
+            LoggerFactory.getLogger(RestDumpResource.class).error(ex.getMessage(), ex);
+        }
+        if (queryResultList==null)
+        {
+            System.err.println("Aborting queryResult is null");
+                return null;
+        }
+        
+        if(!queryResultList.iterator().hasNext()) 
+        {
+            System.err.println("Aborting queryResult does not have next");
+            return null;
+        }//TODO:Throw exception
+        
+        StringBuilder sb = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<tags>\n");
+        
+        Iterator it  = queryResultList.iterator();
+        while (it.hasNext()) {
+                System.out.println("results: +++");
+                SearchResult r = (SearchResult) it.next();
+                for (String s : r.getExtraData().keySet())
+                {
+                    System.out.println(s);
+                    sb.append("\t<tag name=\"").append(s).append("\">").append(escapeHtml3(((String)r.getExtraData().get(s)).trim())).append("</tag>\n");
+                }
+        }
+
+        
+        sb.append("</tags>");
+        
+        //and returns an xml version of our dim search
+        return sb.toString();
+        
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestEnumField.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestEnumField.java
new file mode 100755
index 0000000..e42627c
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestEnumField.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.io.StringWriter;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import org.restlet.data.MediaType;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.server.web.rest.elements.JaxbStrList;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class RestEnumField extends ServerResource{
+
+    
+    
+    @Get
+    public Representation represent(){
+        StringRepresentation sr;
+        /*
+        IndexEngine core = IndexEngine.getInstance();
+        String field = getRequest().getResourceRef().getQueryAsForm().getValues("field");
+        String type = getRequest().getResourceRef().getQueryAsForm().getValues("type");
+
+        if(field == null){
+            return new StringRepresentation("", MediaType.APPLICATION_XML);
+        }
+        
+        if(type == null){
+            type = "text";
+        }
+        
+        Set<String> enumList = null;
+        
+        if(type.equalsIgnoreCase("text")){
+            enumList = core.enumField(field, false);
+        }
+        else if(type.equalsIgnoreCase("float")){
+            enumList = core.enumField(field, true);
+        }
+
+        JaxbStrList jaxbList = new JaxbStrList(enumList);
+
+        StringWriter sw = new StringWriter();
+
+        try {
+            JAXBContext context = JAXBContext.newInstance(JaxbStrList.class);
+            Marshaller m = context.createMarshaller();
+            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+
+            m.marshal(jaxbList, sw);
+
+            sr = new StringRepresentation(sw.toString(), MediaType.APPLICATION_XML);
+
+        } catch (Exception ex) {
+            LoggerFactory.getLogger(RestTagsResource.class).error(ex.getMessage(), ex);
+            
+            sr = new StringRepresentation("", MediaType.APPLICATION_XML);
+        }
+
+        return sr;*/
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestFileResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestFileResource.java
new file mode 100755
index 0000000..51ef740
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestFileResource.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.io.*;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.io.IOUtils;
+import org.restlet.data.MediaType;
+import org.restlet.representation.OutputRepresentation;
+import org.restlet.representation.StreamRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.server.web.rest.elements.FileDownloadUtils;
+
+/**
+ *
+ * @author psytek
+ *
+ * WARNING: This will return *any* file on the host! The best way to correct
+ * this will be to change the generated XML in order to produce SOPInstanceUID,
+ * and let them act as a tag for the file. This will imply a new query every
+ * time we wanto to download a new file, but that's probably fine...
+ *
+ */
+public class RestFileResource extends ServerResource {
+
+    private PluginController core;
+
+    public RestFileResource() {
+        this.core = PluginController.getInstance();
+    }
+    
+    @Get
+    public StreamRepresentation represent() {
+        String SOPInstanceUID = getRequest().getResourceRef().getQueryAsForm().getValues("uid");
+        if (SOPInstanceUID == null) {
+            return null;
+        }
+        return FileDownloadUtils.gerFileRepresentation(SOPInstanceUID);
+        /*File file = new File(queryResultList.get(0).getOrigin());
+        
+        File temp = file;
+        if (file.getAbsolutePath().endsWith(".gz"))
+        {
+            try {
+                temp = File.createTempFile(SOPInstanceUID, Platform.homePath() + ".dcm");
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(RestWADOResource.class).error(ex.getMessage(), ex);
+            }
+            temp.deleteOnExit();
+            FileOutputStream fos;
+            try {
+                fos = new FileOutputStream(temp);
+                BufferedOutputStream bos = new BufferedOutputStream(fos);
+                GZIPInputStream gz = new GZIPInputStream(new BufferedInputStream(new FileInputStream(file)));
+                int byte_;
+                while ((byte_ = gz.read()) != -1)
+                    bos.write(byte_);
+                bos.close();
+                gz.close();
+            } catch (Exception ex) {
+                LoggerFactory.getLogger(RestWADOResource.class).error(ex.getMessage(), ex);
+            }
+
+        }*/
+    }
+    
+     private static class MyHolder extends JointQueryTask {
+         
+        @Override
+        public void onCompletion() {
+        }
+
+        @Override
+        public void onReceive(Task<Iterable<SearchResult>> e) {
+        }
+    }    
+     
+     private static class MyOutput extends OutputRepresentation{
+
+         private StorageInputStream stream;
+
+        public MyOutput(StorageInputStream stream, MediaType mediaType) {
+            super(mediaType);
+            this.stream = stream;
+        }
+        @Override
+        public void write(OutputStream out) throws IOException  {
+            try {
+                IOUtils.copy(stream.getInputStream(), out);
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(RestFileResource.class).error(ex.getMessage(), ex);
+                ex.printStackTrace();
+                throw ex;
+            }
+        }
+     }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestImageResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestImageResource.java
new file mode 100644
index 0000000..4a80a0a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestImageResource.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.zip.GZIPInputStream;
+import org.restlet.data.MediaType;
+import org.restlet.representation.OutputRepresentation;
+import org.restlet.representation.Representation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class RestImageResource extends ServerResource {
+
+    @Get
+    public Representation represent() {/*
+        String SOPInstanceUID = getRequest().getResourceRef().getQueryAsForm().getValues("uid");
+        if (SOPInstanceUID == null) {
+            return null;
+        }
+
+        String heightString = getRequest().getResourceRef().getQueryAsForm().getValues("height");
+        int height = 0;
+
+        if (heightString != null) {
+            try {
+                height = Integer.valueOf(heightString);
+            } catch (NumberFormatException ex) {
+            };
+        }
+
+        IndexEngine core = IndexEngine.getInstance();
+        ArrayList<String> extra = new ArrayList<String>();
+        extra.add("SOPInstanceUID");
+        String query = "SOPInstanceUID:" + SOPInstanceUID;
+        List<SearchResult> queryResultList = core.search(query, extra);
+        if (queryResultList.size() < 1) {
+            return null;//TODO:Throw exception
+        }
+        for (SearchResult r : queryResultList) {
+            LoggerFactory.getLogger(RestDimResource.class.getName()).error(r.getOrigin());
+        }
+        File file = new File(queryResultList.get(0).getOrigin());
+
+        return new DynamicFileRepresentation(MediaType.IMAGE_JPEG, file, height);
+    }
+
+    public class DynamicFileRepresentation extends OutputRepresentation {
+
+        private File dicomImage;
+        private int height;
+
+        public DynamicFileRepresentation(MediaType mediaType, File dicomImage, int height) {
+            super(mediaType);
+            
+            this.dicomImage = dicomImage;
+            this.height = height;
+            
+            
+            
+            if (dicomImage.getAbsolutePath().endsWith(".gz"))
+            {
+                File temp = null;
+                try {
+                    temp = File.createTempFile(dicomImage.getName(), Platform.homePath() + ".dcm");
+                } catch (IOException ex) {
+                    LoggerFactory.getLogger(RestWADOResource.class).error(ex.getMessage(), ex);
+                }
+                temp.deleteOnExit();
+                FileOutputStream fos;
+                try {
+                    fos = new FileOutputStream(temp);
+                    BufferedOutputStream bos = new BufferedOutputStream(fos, 256);
+                    GZIPInputStream gz = new GZIPInputStream(new BufferedInputStream(new FileInputStream(dicomImage), 256));
+                    int byte_;
+                    while ((byte_ = gz.read()) != -1)
+                        bos.write(byte_);
+                    bos.close();
+                    gz.close();
+                } catch (Exception ex) {
+                    LoggerFactory.getLogger(RestWADOResource.class).error(ex.getMessage(), ex);
+                }
+                dicomImage = temp;
+            }*/
+        throw new UnsupportedOperationException();
+        }
+
+        /*@Override
+        public void write(OutputStream outputStream) throws IOException {
+            Dicom2JPEG.convertDicom2Jpeg(dicomImage, outputStream, height);
+        }*/
+    //}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestTagsResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestTagsResource.java
new file mode 100755
index 0000000..cd8983a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestTagsResource.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+import org.restlet.data.MediaType;
+import org.restlet.representation.Representation;
+import org.restlet.representation.StringRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+
+/**
+ *
+ * @author Samuel Campos <samuelcampos at ua.pt>
+ */
+public class RestTagsResource extends ServerResource {
+
+    @Get
+    public Representation representXML() {
+        StringRepresentation sr;
+        
+        HashMap<String, Integer> tagList = DictionaryAccess.getInstance().getTagList();
+        
+        ArrayList<String> list = new ArrayList<String>();
+        Element tags = new Element("tags");
+        for(String tag : tagList.keySet()){
+               int value = tagList.get(tag);
+               
+               Element e = new Element("tag");
+               e.setAttribute( "id", Integer.toString(value));
+               e.setAttribute("name", tag);
+               tags.addContent(e);
+        } 
+        
+        tags.setAttribute("count", Integer.toString(tags.getChildren().size()));
+        Document xmlDoc = new Document(tags);
+        
+        XMLOutputter out = new XMLOutputter(Format.getCompactFormat());
+        String str = out.outputString(xmlDoc);
+        
+        StringRepresentation rep = new StringRepresentation( str, MediaType.APPLICATION_XML);
+       
+        return rep;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestWADOResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestWADOResource.java
new file mode 100755
index 0000000..be9f989
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/RestWADOResource.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import org.restlet.data.Status;
+import org.restlet.representation.OutputRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.server.web.rest.elements.FileDownloadUtils;
+
+/**
+ *
+ * @author psytek
+ *
+ * WARNING: This will return *any* file on the host! The best way to correct
+ * this will be to change the generated XML in order to produce SOPInstanceUID,
+ * and let them act as a tag for the file. This will imply a new query every
+ * time we want to download a new file, but that's probably fine...
+ *
+ */
+public class RestWADOResource extends ServerResource {
+    
+    @Get
+    public OutputRepresentation represent() {
+        String studyUID = getRequest().getResourceRef().getQueryAsForm().getValues("studyUID");
+        String seriesUID = getRequest().getResourceRef().getQueryAsForm().getValues("seriesUID");
+        String objectUID = getRequest().getResourceRef().getQueryAsForm().getValues("objectUID");
+        String requestType = getRequest().getResourceRef().getQueryAsForm().getValues("requestType");
+        String contentType = getRequest().getResourceRef().getQueryAsForm().getValues("contentType");
+
+        
+
+        setStatus( Status.SUCCESS_OK );
+        //lets make sure that all the REQUIRED (all caps, according to standard :)) are here
+        if(objectUID==null || objectUID.isEmpty())
+        {
+            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+            //result = generateErrorRepresentation("Please enter a UID", "400");
+            //400 means bad request
+        }
+
+        //the standard also requires that the request type is present and == WADO
+        if(requestType == null || !requestType.equals("WADO")){
+                setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
+        }
+        
+        return FileDownloadUtils.gerFileRepresentation(objectUID);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/TestResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/TestResource.java
new file mode 100644
index 0000000..0f268eb
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/TestResource.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.rest;
+
+import org.restlet.data.Parameter;
+import org.restlet.data.Status;
+import org.restlet.resource.Delete;
+import org.restlet.resource.Get;
+import org.restlet.resource.Post;
+import org.restlet.resource.Put;
+import org.restlet.resource.ResourceException;
+import org.restlet.resource.ServerResource;
+
+/**
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class TestResource extends ServerResource {
+    private String something;
+    private boolean really;
+
+    protected boolean getQSBoolean(String name) {
+        Parameter param = getRequest().getResourceRef().getQueryAsForm().getFirst(name);
+        return param != null && (param.getValue() == null || param.getValue().equalsIgnoreCase("true"));
+    }
+    
+    @Override
+    public void doInit() {
+        super.doInit();
+        something = (String) getRequest().getAttributes().get("something");
+        really = getQSBoolean("really");
+    }
+    
+    @Get("txt")
+    public String testGet() {
+        return (really ? "REALLY " : "") + something + " GET";
+    }
+
+    @Post("txt:txt")
+    public String testPost(String data) {
+        if (something == null || something.isEmpty()) {
+            throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST);
+        }
+        return (really ? "REALLY " : "") + something + " POST: " + data;
+    }
+
+    @Put("txt")
+    public String testPut() {
+        return (really ? "REALLY " : "") + something + " PUT";
+    }
+
+    @Delete("txt")
+    public String testDelete() {
+        return (really ? "REALLY " : "") + something + " DELETE";
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/VersionResource.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/VersionResource.java
new file mode 100644
index 0000000..c259aca
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/VersionResource.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest;
+
+import org.restlet.data.MediaType;
+import org.restlet.ext.json.JsonRepresentation;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import pt.ua.dicoogle.core.Version;
+
+/**
+ * Created by bastiao on 23/09/15.
+ */
+public class VersionResource extends ServerResource {
+
+    @Get("json")
+    public JsonRepresentation represent() {
+        
+        Version v = new Version();
+        JsonRepresentation sr = new JsonRepresentation("{\"version\":\""+v.getVersion()+
+                "\"}");
+
+        sr.setMediaType(MediaType.APPLICATION_JSON);
+
+        return sr;
+
+    }
+    
+    @Override
+    public String toString(){
+        return "version";
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/ExamTimeCore.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/ExamTimeCore.java
new file mode 100644
index 0000000..6951fee
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/ExamTimeCore.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package pt.ua.dicoogle.server.web.rest.elements;
+
+import java.io.File;
+
+/**
+ *
+ * @author samuelcampos
+ */
+public class ExamTimeCore {
+
+    private static final String examTimeFile = "ExamTime.csv";
+    private static ExamTimeCore instance;
+    private ExamTimeState actualState;
+    private File file;
+    private TExamTime thread = null;
+    private int total;
+    private int i;
+
+    public synchronized static ExamTimeCore getInstance() {
+        if (instance == null) {
+            instance = new ExamTimeCore();
+        }
+
+        return instance;
+    }
+
+    private ExamTimeCore() {
+        file = new File(examTimeFile);
+
+        if (file.exists()) {
+            actualState = ExamTimeState.READY;
+        } else {
+            actualState = ExamTimeState.EMPTY;
+        }
+    }
+    
+    
+    public synchronized File getFile(){
+        if(actualState.equals(ExamTimeState.READY))
+            return file;
+        
+        return null;
+    }
+    
+    public synchronized void startThread(){
+        if(thread != null){
+            thread.stopThread();
+        }
+        
+        i = 0;
+        
+        thread = new TExamTime(file);
+//        thread.setPriority(Thread.MIN_PRIORITY);
+        thread.start();
+        
+        actualState = ExamTimeState.RUNNING;
+    }
+    
+    public synchronized void stopThread(){
+        if(thread != null){
+            thread.stopThread();
+            
+            file.delete(); // Apaga o ficheiro pois ele não está acabado
+        }
+        
+        thread = null;
+        
+        actualState = ExamTimeState.EMPTY;
+    }
+    
+    protected synchronized void threadFinished(){        
+        thread = null;
+        actualState = ExamTimeState.READY;
+    }
+    
+    protected synchronized void setTotal(int total){
+        this.total = total;
+    }
+    protected synchronized void increment(){
+        i++;
+    }
+    public synchronized float getPercentage(){
+        return ((float) i) / ((float) total) * 100;
+    }
+    
+
+    public synchronized ExamTimeState getState() {
+        return actualState;
+    }
+
+    public enum ExamTimeState {
+
+        EMPTY,
+        RUNNING,
+        READY
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/FileDownloadUtils.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/FileDownloadUtils.java
new file mode 100644
index 0000000..b893896
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/FileDownloadUtils.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package pt.ua.dicoogle.server.web.rest.elements;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.restlet.data.Disposition;
+import org.restlet.data.MediaType;
+import org.restlet.representation.OutputRepresentation;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.server.web.rest.RestDimResource;
+import pt.ua.dicoogle.server.web.rest.RestFileResource;
+
+/**
+ *
+ * @author tiago
+ */
+public class FileDownloadUtils {
+    
+    public static OutputRepresentation gerFileRepresentation(String SOPInstanceUID) {
+        String query = "SOPInstanceUID:" + SOPInstanceUID;
+        
+        HashMap<String, String> extraFields = new HashMap<>();
+        extraFields.put("SOPInstanceUID", "SOPInstanceUID");
+        
+        PluginController pc = PluginController.getInstance();
+        JointQueryTask task = new MyHolder();
+        pc.queryAll(task, query, extraFields);
+        Iterable<SearchResult> queryResults = null;
+        try {
+            queryResults = task.get();
+        } catch (InterruptedException | ExecutionException ex) {
+            LoggerFactory.getLogger(RestFileResource.class).error(ex.getMessage(), ex);
+            return null;
+        }
+        
+        if(!queryResults.iterator().hasNext())
+            return null;
+        
+        URI fileURI = null;
+        for (SearchResult r : queryResults) {
+            LoggerFactory.getLogger(RestDimResource.class).error(r.getURI().toString());
+            fileURI = r.getURI();
+        }
+
+        Iterable<StorageInputStream> str = pc.resolveURI(fileURI);
+        if(!str.iterator().hasNext())
+            return null;
+        
+        for(StorageInputStream s : str){
+            MyOutput out = new MyOutput(s, MediaType.register("application/dicom", 
+          "dicom medical data file"));
+            
+            System.out.println("Setting File Type");
+            Disposition d = new Disposition(Disposition.TYPE_ATTACHMENT);
+            String name = FilenameUtils.getName(s.getURI().getPath());
+            if(name.isEmpty())
+                name = "Downloaded.dcm";
+            d.setFilename(name);
+            
+                
+            out.setDisposition(d);
+            
+            return out;
+        }
+        return null;
+    }
+        
+    private static class MyHolder extends JointQueryTask {
+         
+        @Override
+        public void onCompletion() {
+        }
+
+        @Override
+        public void onReceive(Task<Iterable<SearchResult>> e) {
+        }
+    }    
+     
+     private static class MyOutput extends OutputRepresentation{
+
+         private final StorageInputStream stream;
+
+        public MyOutput(StorageInputStream stream, MediaType mediaType) {
+            super(mediaType);
+            this.stream = stream;
+        }
+        @Override
+        public void write(OutputStream out) throws IOException  {
+             try {
+                 IOUtils.copy(stream.getInputStream(), out);
+             } catch (IOException ex) {
+                 LoggerFactory.getLogger(RestFileResource.class).error(ex.getMessage(), ex);
+                 throw ex;
+             }
+           
+        }
+     }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/JaxbStrList.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/JaxbStrList.java
new file mode 100644
index 0000000..1cff813
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/JaxbStrList.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest.elements;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ *
+ * @author samuelcampos
+ */
+ at XmlRootElement(name="List")
+public class JaxbStrList{
+    @XmlElement(name="Item")
+    public List<String> list;
+
+    public JaxbStrList(){}
+    
+    public JaxbStrList(List<String> list){
+        this.list=list;
+    }
+    
+    public JaxbStrList(Set<String> set){
+        
+        this.list = new ArrayList<String>();
+        this.list.addAll(set);
+        
+        Collections.sort(list);
+    }
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/TExamTime.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/TExamTime.java
new file mode 100644
index 0000000..88cd753
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/rest/elements/TExamTime.java
@@ -0,0 +1,246 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.rest.elements;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author samuelcampos
+ */
+public class TExamTime extends Thread {
+
+    private File file;
+    private boolean stop = false;
+
+    public TExamTime(File file) {
+        if (file.isDirectory()) {
+            throw new IllegalArgumentException("Invalid FILE");
+        }
+
+        this.file = file;
+    }
+
+    public synchronized void stopThread() {
+        if(stop)
+            return; // A Thread j?? parou ou est?? a parar
+        
+        stop = true;
+
+        try {
+            while (stop == true) {
+                wait();
+            }
+        } catch (InterruptedException ex) {
+            LoggerFactory.getLogger(TExamTime.class).error(ex.getMessage(), ex);
+        }
+    }
+
+    @Override
+    public void run() {
+        throw new UnsupportedOperationException();/*
+        long beginTime = System.currentTimeMillis();
+        long endTime;
+        ExamTimeCore examTime = ExamTimeCore.getInstance();
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(file, false));
+
+
+            IndexEngine core = IndexEngine.getInstance();
+
+            Set<String> enumList = core.enumField("AccessionNumber", false);
+            
+            examTime.setTotal(enumList.size());
+
+            List<String> extrafields = new ArrayList<String>();
+            extrafields.add("SeriesInstanceUID");
+            extrafields.add("AcquisitionDateTime");
+            extrafields.add("AcquisitionTime");
+            extrafields.add("AcquisitionDate");
+
+
+            int i = 0, j = 0, k = 0;
+            for (String accessionNumber : enumList) {
+
+                List<SearchResult> results = core.searchSync("AccessionNumber:" + accessionNumber, extrafields);
+
+                HashMap<String, List<String>> DateTimes = new HashMap<String, List<String>>();
+
+                for (SearchResult result : results) {
+                    synchronized (this) {
+                        if (stop) {
+                            stop = false;
+                            out.close();
+                            
+                            notify();
+                            return;
+                        }
+                    }
+
+
+                    Hashtable<String, String> fields = result.getExtrafields();
+
+                    String SeriesInstanceUID = fields.get("SeriesInstanceUID");
+
+                    if (SeriesInstanceUID == null) {
+                        // Its not possible to calculate the Series Time!
+                        throw new NullPointerException("SeriesInstanceUID IS NULL!!!!");
+                    }
+
+                    String time = fields.get("AcquisitionDateTime");
+
+                    if (time != null) {
+                        List<String> lt = DateTimes.get(SeriesInstanceUID);
+
+                        if (lt == null) {
+                            lt = new ArrayList<String>();
+                            DateTimes.put(SeriesInstanceUID, lt);
+                        }
+
+                        lt.add(time);
+
+                    } else {
+                        time = fields.get("AcquisitionTime");
+                        String date = fields.get("AcquisitionDate");
+
+                        if (time != null) {
+                            if (date == null) {
+                                throw new NullPointerException("DATE IS NULL!!!!");
+                            }
+
+                            List<String> lt = DateTimes.get(SeriesInstanceUID);
+
+                            if (lt == null) {
+                                lt = new ArrayList<String>();
+                                DateTimes.put(SeriesInstanceUID, lt);
+                            }
+
+                            lt.add(date + time);
+                        } else {
+                            k++;
+                        }
+                    }
+
+                    j++;
+                }
+
+                if (!DateTimes.isEmpty()) {
+                    HashMap<String, SimpleEntry<Integer, Integer>> times = getSeriesDateTimes(DateTimes);
+
+                    writeFileLine(out, accessionNumber, times.values());
+                }
+                
+                
+                examTime.increment();
+
+//                i++;
+//
+//                if (i == 50) {
+//                    break;
+//                }
+            }
+            
+            examTime.threadFinished();
+            
+        } catch (Exception ex) {
+            LoggerFactory.getLogger(TExamTime.class).error(ex.getMessage(), ex);
+        } finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(TExamTime.class).error(ex.getMessage(), ex);
+            }
+        }
+
+        synchronized (this) {
+            stop = true;
+            notify();
+        }
+        
+        endTime = System.currentTimeMillis();
+        
+        System.out.println("SpentTime (ms): " + (endTime - beginTime));*/
+    }
+
+    private void writeFileLine(BufferedWriter out, String accessionNumber, Collection<SimpleEntry<Integer, Integer>> times) throws IOException {
+        StringBuilder st = new StringBuilder();
+
+        st.append(accessionNumber).append(";");
+
+        for (SimpleEntry<Integer, Integer> time : times) {
+            st.append(time.getKey()).append(";").append(time.getValue()).append(";");
+        }
+        st.deleteCharAt(st.length()-1); 
+        st.append("\n");
+
+
+        out.write(st.toString());
+    }
+
+    /**
+     * Calcula o tempo de dura????o de cada uma das S??ries, dado tempos em "Ano,
+     * M??s, Dia, Hora, Minuto, Segundo"
+     *
+     * @param dateTime
+     * @return
+     */
+    private HashMap<String, SimpleEntry<Integer, Integer>> getSeriesDateTimes(HashMap<String, List<String>> dateTime) {
+        HashMap<String, SimpleEntry<Integer, Integer>> result = new HashMap<String, SimpleEntry<Integer, Integer>>();
+
+        for (String SeriesInstanceUID : dateTime.keySet()) {
+            List<String> times = dateTime.get(SeriesInstanceUID);
+
+            int min = Integer.MAX_VALUE;
+            int max = Integer.MIN_VALUE;
+
+
+            for (String time : times) {
+                Calendar cal = Calendar.getInstance();
+                cal.set(Integer.valueOf(time.substring(0, 4)), Integer.valueOf(time.substring(4, 6)), Integer.valueOf(time.substring(6, 8)), Integer.valueOf(time.substring(8, 10)), Integer.valueOf(time.substring(10, 12)), Integer.valueOf(time.substring(12, 14)));
+
+                int actual = (int) (cal.getTimeInMillis() / 1000);
+
+                if (actual < min) {
+                    min = actual;
+                }
+
+                if (actual > max) {
+                    max = actual;
+                }
+            }
+
+            result.put(SeriesInstanceUID, new SimpleEntry<Integer, Integer>((max - min), times.size()));
+        }
+
+        return result;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportCSVToFILEServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportCSVToFILEServlet.java
new file mode 100644
index 0000000..b409e98
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportCSVToFILEServlet.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.core.query.ExportToCSVQueryTask;
+import pt.ua.dicoogle.plugins.PluginController;
+
+public class ExportCSVToFILEServlet extends HttpServlet {
+	private static final Logger logger = LoggerFactory.getLogger(ExportCSVToFILEServlet.class);
+
+	private File tempDirectory;
+	public ExportCSVToFILEServlet(File tempDirectory) {
+		super();
+		this.tempDirectory = tempDirectory;
+	}
+
+	private static final long serialVersionUID = 1L;
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		String uid = req.getParameter("UID");
+		if(uid == null){
+			resp.sendError(401, "No Query UID Supplied: Please fill the field \"UID\"");
+			return;
+		}
+		
+		File tmpFile = new File(tempDirectory, "QueryResultsExport-"+uid);
+		if(!tmpFile.exists()){
+			resp.sendError(402, "The file for the given uid was not found. Please try again...");
+			return; 
+		}
+		
+		// Find this file id in database to get file name, and file type
+
+        // You must tell the browser the file type you are going to send
+        // for example application/pdf, text/plain, text/html, image/jpg
+        resp.setContentType("application/csv");
+        // Make sure to show the download dialog
+        resp.setHeader("Content-disposition","attachment; filename=QueryResultsExport.csv");		
+		
+		try (BufferedInputStream bi = new BufferedInputStream(new FileInputStream(tmpFile))) {
+
+			IOUtils.copy(bi, resp.getOutputStream());
+			resp.getOutputStream().flush();
+		}
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		List<String> orderedFields = new ArrayList<>();
+		Map<String, String> fields = new HashMap<>();
+		String queryString = null;
+		String[] arr;		
+		boolean keyword;
+		
+		try {
+			queryString = req.getParameter("query");
+			if (queryString == null) {
+				resp.sendError(402,
+						"QueryString not supplied: Please fill the field \"query\"");
+				return;
+			}
+
+			System.out.println(req.getParameter("fields"));
+			JSONArray jsonObj = new JSONArray().fromObject(req.getParameter("fields"));
+			if (jsonObj.size()== 0) {
+				resp.sendError(403,
+						"No fields supplied: Please fill the field \"extraFields\" in \"JSON\"");
+				return;
+			}
+
+			for (Object f : jsonObj) {
+				fields.put(f.toString(), f.toString());
+				orderedFields.add(f.toString());
+			}
+			keyword = Boolean.parseBoolean(req.getParameter("keyword"));
+
+			arr = req.getParameterValues("providers");
+		} catch (JSONException ex) {
+			resp.sendError(400, "Invalid JSON content");
+			return;
+		}
+		
+		if (!keyword) {
+            QueryExpressionBuilder q = new QueryExpressionBuilder(queryString);
+            queryString = q.getQueryString();
+        }
+
+		String uid = UUID.randomUUID().toString();
+		//File tempFile = File.createTempFile("QueryResultsExport-", uid, tempDirectory);
+		File tempFile = new File(tempDirectory, "QueryResultsExport-"+uid);
+		tempFile.deleteOnExit();
+		logger.debug("UID: {}", uid);
+		logger.debug("FilePath: {}", tempFile.getAbsolutePath());
+		
+		FileOutputStream outStream = new FileOutputStream(tempFile);
+		BufferedOutputStream bos = new BufferedOutputStream(outStream);
+		
+		ExportToCSVQueryTask task = new ExportToCSVQueryTask(orderedFields,
+				bos);
+		
+		if (arr == null || arr.length ==0) {
+			PluginController.getInstance().queryAll(task, queryString, fields);
+		} else {
+			List<String> providers = new ArrayList<>();
+			for (Object f : arr) {
+				providers.add(f.toString());
+			}
+			PluginController.getInstance().query(task, providers, queryString,
+					fields);
+		}
+
+		task.await();
+		
+		JSONObject obj = new JSONObject();
+		obj.put("uid", uid);
+		resp.getWriter().write(obj.toString());
+		resp.getWriter().flush();
+	}
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportToCSVServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportToCSVServlet.java
new file mode 100644
index 0000000..5a69e9a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ExportToCSVServlet.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.core.query.ExportToCSVQueryTask;
+import pt.ua.dicoogle.plugins.PluginController;
+
+/**
+ * @author fredericosilva at ua.pt
+ */
+public class ExportToCSVServlet extends HttpServlet {
+
+	private static final long serialVersionUID = 1L;
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		resp.setHeader("Content-disposition","attachment; filename=QueryResultsExport.csv");
+		String queryString = req.getParameter("query");
+		String[] fields = req.getParameterValues("fields");
+		String[] providers = req.getParameterValues("providers");
+		
+		if(queryString == null)
+			resp.sendError(401, "Query Parameters not found");
+		
+		if(fields == null || fields.length==0)
+			resp.sendError(402, "Fields Parameters not found");
+						    	
+	    List<String> fieldList = new ArrayList<>(fields.length);
+	    Map<String, String> fieldsMap = new HashMap<>();
+	    for(String f : fields){
+	    	fieldList.add(f);
+	    	fieldsMap.put(f, f);
+	    }
+	    	    	    
+    	ExportToCSVQueryTask task = new ExportToCSVQueryTask( fieldList,
+				resp.getOutputStream());
+
+    	if(providers == null || providers.length == 0) {
+			PluginController.getInstance().queryAll(task, queryString, fieldsMap);
+		} else {
+			List<String> providersList = new ArrayList<>();
+			for (String f : providers) {
+				providersList.add(f);
+			}
+			PluginController.getInstance().query(task, providersList, queryString,
+					fieldsMap);
+		}
+
+		task.await();
+	}
+	
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		// TODO Auto-generated method stub
+		String dataString = req.getParameter("JSON-DATA");
+		if (dataString == null) {
+			resp.sendError(401,
+					"No data suplied: Please fill the field \"JSON-DATA\"");
+			return;
+		}
+
+		List<String> orderedFields = new ArrayList<>();
+		Map<String, String> fields = new HashMap<>();
+		String queryString = null;
+		JSONArray arr;		
+		
+		try {
+			JSONObject data = JSONObject.fromObject(dataString);
+			queryString = data.getString("queryString");
+			if (queryString == null) {
+				resp.sendError(
+						402,
+						"QueryString no suplied: Please fill the field \"queryString\" in \"JSON-DATA\"");
+				return;
+			}
+
+			arr = data.getJSONArray("extraFields");
+			if (arr.isEmpty()) {
+				resp.sendError(403,
+						"No fields no suplied: Please fill the field \"extraFiekds\" in \"JSON-DATA\"");
+				return;
+			}
+
+			for (Object f : arr) {
+				fields.put(f.toString(), f.toString());
+				orderedFields.add(f.toString());
+			}
+
+			arr = data.getJSONArray("providers");
+		} catch (JSONException ex) {
+			resp.sendError(400,
+					"Error parsing the JSON String: " + ex.toString());
+			return;
+		}
+
+		ExportToCSVQueryTask task = new ExportToCSVQueryTask(orderedFields,
+				resp.getOutputStream());
+
+		if (arr.isEmpty()) {
+			PluginController.getInstance().queryAll(task, queryString, fields);
+		} else {
+			List<String> providers = new ArrayList<>();
+			for (Object f : arr) {
+				providers.add(f.toString());
+			}
+			PluginController.getInstance().query(task, providers, queryString,
+					fields);
+		}
+
+		task.await();
+		
+	}
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ImageServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ImageServlet.java
new file mode 100644
index 0000000..df8a3c3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/ImageServlet.java
@@ -0,0 +1,252 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import javax.servlet.ServletOutputStream;
+
+import net.sf.json.JSONObject;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.server.web.dicom.Convert2PNG;
+import pt.ua.dicoogle.server.web.dicom.Information;
+import pt.ua.dicoogle.server.web.utils.LocalImageCache;
+
+/**
+ * Handles the requests for DICOM frames, returning them as PNG images.
+ * Also maintains a cache of the images already served to speed-up the next requests (minimizing server load by doing way less conversions).
+ *
+ * @author Antonio
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class ImageServlet extends HttpServlet
+{
+    private static final Logger logger = LoggerFactory.getLogger(ImageServlet.class);
+    private static final long serialVersionUID = 1L;
+
+    public static final int BUFFER_SIZE = 1500; // byte size for read-write ring bufer, optimized for regular TCP connection windows
+
+    private final LocalImageCache cache;
+	
+    /**
+     * Creates an image servlet.
+     *
+     * @param cache the local image caching system, can be null and if so no caching mechanism will be used.
+     */
+    public ImageServlet(LocalImageCache cache) {
+        this.cache = cache;
+    }
+    
+	@Override
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+	{
+		String sopInstanceUID = request.getParameter("SOPInstanceUID");
+		String uri = request.getParameter("uri");
+        boolean thumbnail = Boolean.valueOf(request.getParameter("thumbnail"));
+        
+		if (sopInstanceUID == null) {
+            if (uri == null) {
+                response.sendError(400, "URI or SOP Instance UID not provided");
+                return;
+            }
+        } else if (sopInstanceUID.trim().isEmpty()) {
+			response.sendError(400, "Invalid SOP Instance UID!");
+			return;
+		}
+		String[] providerArray = request.getParameterValues("provider");
+        List<String> providers = providerArray == null ? null : Arrays.asList(providerArray);
+		String sFrame = request.getParameter("frame");
+        int frame;
+		if (sFrame == null) {
+            frame = 0;
+        } else {
+            frame = Integer.parseInt(sFrame);
+        }
+        
+        StorageInputStream imgFile;
+        if (sopInstanceUID != null) {
+            // get the image file for that SOP Instance UID
+            imgFile = getFileFromSOPInstanceUID(sopInstanceUID, providers);
+            // if no .dcm file was found tell the client
+            if (imgFile == null) {
+                response.sendError(404, "No image file for supplied SOP Instance UID!");
+                return;
+            }
+        } else {
+            try {
+                // get the image file by the URI
+                URI imgUri = new URI(uri);
+                StorageInterface storageInt = PluginController.getInstance().getStorageForSchema(imgUri);
+                Iterator<StorageInputStream> storages = storageInt.at(imgUri).iterator();
+                // take the first valid storage
+                if (!storages.hasNext()) {
+                    response.sendError(404, "No image file for supplied URI!");
+                    return;
+                }
+                imgFile = storages.next();
+                 
+            } catch (URISyntaxException ex) {
+                response.sendError(400, "Bad URI syntax");
+                return;
+            }
+        }
+
+		// if there is a cache available then use it
+		if (cache != null && cache.isRunning()) {
+
+            try {
+                InputStream istream = cache.get(imgFile.getURI(), frame, thumbnail);
+                response.setContentType("image/png");
+                try(ServletOutputStream out = response.getOutputStream()) {
+                    IOUtils.copy(istream, out);
+                }
+            } catch (IOException ex) {
+                logger.warn("Could not convert the image", ex);
+                response.sendError(500);
+            } catch (RuntimeException ex) {
+                logger.error("Unexpected exception", ex);
+                response.sendError(500);
+            }
+            
+ 		} else {
+            // if the cache is invalid or not running convert the image and return it "on-the-fly"
+            try {
+                ByteArrayOutputStream pngStream = getPNGStream(imgFile, frame, thumbnail);
+                response.setContentType("image/png"); // set the appropriate type for the PNG image
+                response.setContentLength(pngStream.size()); // set the image size
+                try (ServletOutputStream out = response.getOutputStream()) {
+                    pngStream.writeTo(out);
+                    pngStream.flush();
+                }
+            } catch (IOException ex) {
+                logger.warn("Could not convert the image", ex);
+                response.sendError(500, "Could not convert the image");
+            }
+		}
+    }
+    
+    private ByteArrayOutputStream getPNGStream(StorageInputStream imgFile, int frame, boolean thumbnail) throws IOException {
+        ByteArrayOutputStream pngStream;
+        if (thumbnail) {
+            int thumbSize;
+            try {
+                // retrieve thumbnail dimension settings
+                thumbSize = Integer.parseInt(ServerSettings.getInstance().getThumbnailsMatrix());
+            } catch (NumberFormatException ex) {
+                logger.warn("Failed to parse ThumbnailMatrix, using default thumbnail size");
+                thumbSize = 64;
+            }
+            pngStream = Convert2PNG.DICOM2ScaledPNGStream(imgFile, frame, thumbSize, thumbSize);
+        } else {
+            pngStream = Convert2PNG.DICOM2PNGStream(imgFile, frame);
+        }
+        return pngStream;
+    }
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+        // TODO this service does not make sense as a POST.
+        // either remove or relocate to another resource
+        
+		String sop = req.getParameter("SOPInstanceUID");
+		if(sop == null){
+			resp.sendError(500, "No SOPInstanceUID in Request");
+			return;
+		}
+
+		float frameRate = Information.getFrameRateFromImage(sop);
+		if(frameRate == -1){
+			resp.sendError(500, "Cannot Locate the image File.");
+			return;
+		}
+		
+		int nFrames = Information.getNumberOfFramesInFile(sop);
+		
+		JSONObject r = new JSONObject();
+		r.put("SOPInstanceUID", sop);
+		r.put("NumberOfFrames", nFrames);
+		r.put("FrameRate", frameRate);
+		
+		resp.setContentType("application/json");
+		
+		PrintWriter wr = resp.getWriter();
+		wr.print(r.toString());	
+	}
+	
+    private static StorageInputStream getFileFromSOPInstanceUID(String sopInstanceUID, List<String> providers) throws IOException {
+        // TODO use only DIM sources?
+        JointQueryTask qt = new JointQueryTask() {
+            @Override
+            public void onCompletion() {
+            }
+            @Override
+            public void onReceive(Task<Iterable<SearchResult>> e) {
+            }
+        };
+        try {
+            if (providers == null) {
+                providers = PluginController.getInstance().getQueryProvidersName(true);
+            }
+            Iterator<SearchResult> it = PluginController.getInstance()
+                    .query(qt, providers, "SOPInstanceUID:" + sopInstanceUID).get().iterator();
+            if (!it.hasNext()) {
+                throw new IOException("No such image of SOPInstanceUID " + sopInstanceUID);
+            }
+            SearchResult res = it.next();
+            StorageInterface storage = PluginController.getInstance().getStorageForSchema(res.getURI());
+            if (storage == null) {
+                throw new IOException("Unsupported file scheme");
+            }
+            Iterator<StorageInputStream> store = storage.at(res.getURI()).iterator();
+            if (!store.hasNext()) {
+                throw new IOException("No storage item found");
+            }
+            return store.next();
+        } catch (InterruptedException | ExecutionException ex) {
+            throw new IOException(ex);
+        }
+        
+    }
+    	
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/IndexerServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/IndexerServlet.java
new file mode 100644
index 0000000..3be239a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/IndexerServlet.java
@@ -0,0 +1,439 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Enumeration;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.ServletOutputStream;
+
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.settings.types.ServerDirectoryPath;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.server.web.management.Services;
+import pt.ua.dicoogle.server.web.auth.Session;
+import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.server.web.management.Dicoogle;
+
+/**
+ * Provides indexing start and stop requests (scan path). Also handles requests
+ * for both indexing progress/status and server path contents.
+ * 
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+ at Deprecated
+public class IndexerServlet extends HttpServlet {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public static final String PARAM_ACTION = "action";
+
+	public static final String ACTION_START_INDEXING = "start";
+	public static final String ACTION_STOP_INDEXING = "stop";
+	public static final String ACTION_GET_STATUS = "status";
+	public static final String ACTION_SET_INDEXING_PATH = "setpath";
+	public static final String ACTION_SET_ADVANCED_SETTINGS = "setadvancedsettings";
+	public static final String ACTION_GET_PATH_CONTENTS = "pathcontents";
+	public static final String ACTION_PARAM_PATH = "path";
+
+	/*
+	 * Action codes for internal use.
+	 */
+	private static final int ACTION_CODE_INVALID = 0;
+	private static final int ACTION_CODE_START_INDEXING = 1;
+	private static final int ACTION_CODE_STOP_INDEXING = 2;
+	private static final int ACTION_CODE_GET_STATUS = 3;
+	private static final int ACTION_CODE_SET_INDEXING_PATH = 4;
+	private static final int ACTION_CODE_SET_ADVANCED_SETTINGS = 5;
+	private static final int ACTION_CODE_GET_PATH_CONTENTS = 6;
+
+	/**
+	 * A file filter to allow the listing of directories only.
+	 */
+	private static FileFilter onlyDirectories = new FileFilter() {
+		@Override
+		public boolean accept(File pathname) {
+			return pathname.isDirectory();
+		}
+	};
+
+	private List<Task<Report>> ongoingTasks;
+
+	public IndexerServlet() {
+		this.ongoingTasks = null;
+	}
+
+	/**
+	 * Returns a XML document in String form containing the list of child
+	 * directories of the specified path.
+	 * 
+	 * @param path
+	 *            the path of the directory to retrieve the child directories
+	 *            of.
+	 * @return a XML document in String form containing the list of child
+	 *         directories of the specified path.
+	 */
+	public static String getPathContents(String path) {
+		File dir = null;
+		if (path != null)
+			dir = new File(path);
+
+		// check if the specified path is a valid one, if not revert to "roots"
+		if ((path == null) || path.trim().isEmpty() || (dir == null)
+				|| (!dir.exists()) || (!dir.isDirectory()))
+			path = "";
+		else
+			path = dir.getAbsolutePath();
+
+		// guarantee that the parent path is always a valid one (never null)
+		String parentPath = "";
+		File[] childs = null;
+		if (path.isEmpty()) {
+			// return "roots"
+			childs = File.listRoots();
+		} else {
+			if (dir.getParent() != null) {
+				File parent = new File(dir.getParent());
+				parentPath = parent.getAbsolutePath();
+			}
+			// list the dir children
+			childs = dir.listFiles(onlyDirectories);
+		}
+
+		// create the XML string builder and open the xml document
+		StringBuilder xml = new StringBuilder(
+				"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+		xml.append("<contents path=\"");
+		xml.append(escapeHtml4(path));
+		xml.append("\" parent=\"");
+		xml.append(escapeHtml4(parentPath));
+		xml.append("\">");
+
+		// loop through all the cildren and add their path name to the XML tree
+		if (childs != null) {
+			for (File child : childs) {
+				String cName = child.getName();
+				String cPath = child.getAbsolutePath();
+				if ((cName == null) || cName.isEmpty())
+					cName = cPath;
+
+				xml.append("<directory name=\"");
+				xml.append(escapeHtml4(cName));
+				xml.append("\" path=\"");
+				xml.append(escapeHtml4(cPath));
+				xml.append("\" />");
+			}
+		}
+
+		// close the document
+		xml.append("</contents>");
+
+		// return the formed XML string
+		return xml.toString();
+	}
+
+	/**
+	 * Returns a XML document in String form containing the status of the
+	 * indexing.
+	 * 
+	 * @return a XML document in String form containing the status of the
+	 *         indexing. TODO: fix
+	 */
+	public String getIndexingStatus() {
+		boolean isIndexing = false;
+		int percentCompleted = 0;
+
+		if (this.ongoingTasks != null) {
+			System.out.println("### Status ###");
+			System.out.println("### Number of Tasks : "
+					+ this.ongoingTasks.size());
+			float tempProgess = 0;
+			for (Task<Report> task : this.ongoingTasks) {
+				if (!task.isDone())
+					isIndexing = true;
+				System.out.println("##### $ Progress: " + task.getProgress());
+				System.out.println("##### $ Completed: " + task.isDone());
+				tempProgess += task.getProgress();
+			}
+			percentCompleted = (int) (tempProgess / this.ongoingTasks.size() * 100);
+			if (isIndexing == false)
+				this.ongoingTasks = null;
+		}
+
+		// create the XML string builder and open the xml document
+		StringBuilder xml = new StringBuilder(
+				"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+		xml.append("<status running=\"");
+		xml.append(Boolean.toString(isIndexing));
+		xml.append("\">");
+
+		// add percentage information
+		xml.append("<percent completed=\"");
+		xml.append(percentCompleted);
+		xml.append("\" />");
+
+		// close the document
+		xml.append("</status>");
+
+		// return the formed XML string
+		return xml.toString();
+	}
+
+	/**
+	 * Writes the specified XML document in String form to a HttpServletResponse
+	 * object.
+	 * 
+	 * @param xml
+	 *            a XML document in String form.
+	 * @param response
+	 *            a HttpServletResponse.
+	 * @throws IOException
+	 *             if a error has occurred while writing the response.
+	 */
+	private static void writeXMLToResponse(String xml,
+			HttpServletResponse response, boolean allowCache)
+			throws IOException {
+		// get the returned xml as a UTF-8 byte array
+		byte[] data = xml.getBytes("UTF-8");
+		if (data == null) {
+			response.sendError(500,
+					"Could generate the resulting XML document!");
+			return;
+		}
+
+		if (!allowCache) {
+			response.addHeader("Cache-Control", "no-cache, must-revalidate");
+			response.addHeader("Pragma", "no-cache");
+		}
+
+		response.setContentType("application/xml"); // set the appropriate type
+													// for the XML file
+		response.setContentLength(data.length); // set the document size
+		// response.setCharacterEncoding("UTF-8"); // set the apropriate
+		// encoding type
+
+		// write the XML data to the response output
+		ServletOutputStream out = response.getOutputStream();
+		out.write(data);
+		out.close();
+	}
+
+	@Override
+	protected void doGet(HttpServletRequest request,
+			HttpServletResponse response) throws IOException {
+		// TODO validate user session credentials
+
+		// get which action to take
+		String actionStr = request.getParameter(PARAM_ACTION);
+
+		// translate each action string to a action identification
+		int action = ACTION_CODE_INVALID;
+		if (actionStr != null) {
+			if (actionStr.equalsIgnoreCase(ACTION_START_INDEXING))
+				action = ACTION_CODE_START_INDEXING;
+			else if (actionStr.equalsIgnoreCase(ACTION_STOP_INDEXING))
+				action = ACTION_CODE_STOP_INDEXING;
+			else if (actionStr.equalsIgnoreCase(ACTION_GET_STATUS))
+				action = ACTION_CODE_GET_STATUS;
+			else if (actionStr.equalsIgnoreCase(ACTION_SET_INDEXING_PATH))
+				action = ACTION_CODE_SET_INDEXING_PATH;
+			else if (actionStr.equalsIgnoreCase(ACTION_SET_ADVANCED_SETTINGS))
+				action = ACTION_CODE_SET_ADVANCED_SETTINGS;
+			else if (actionStr.equalsIgnoreCase(ACTION_GET_PATH_CONTENTS))
+				action = ACTION_CODE_GET_PATH_CONTENTS;
+		}
+
+		// response to each action accordingly
+		// fix this!
+		switch (action) {
+		case ACTION_CODE_START_INDEXING:
+			System.err.println("Started Indexing!!");
+
+			Dicoogle dic = Dicoogle.getInstance();
+
+			ServerDirectoryPath thepath = (ServerDirectoryPath) dic
+					.getIndexingSettings().get(
+							"Dicoogle Directory Monitorization");
+
+			System.out.println("Indexing Home: " + thepath.getPath());
+			File f = new File(thepath.getPath());
+			URI uri = f.toURI();
+
+			if (uri != null) {
+				System.out.println("URI: " + uri.toString());
+				List<Task<Report>> report = PluginController.getInstance().index(uri);
+				System.out.println("Report Length: " + report.size());
+				if (this.ongoingTasks == null)
+					this.ongoingTasks = report;
+				else
+					System.out.println("More than one task in queue");
+			} else
+				System.out.println("Faulty");
+			// send the client back the to previous page
+			response.sendRedirect(Session.getLastVisitedURL(request));
+			break;
+
+		case ACTION_CODE_STOP_INDEXING:
+			// idx.stopIndexing();
+			// send the client back the to previous page
+
+			// Cancelling all Tasks
+			if (this.ongoingTasks != null) {
+				for (Task<Report> t : this.ongoingTasks)
+					t.cancel(true);
+			}
+
+			response.sendRedirect(Session.getLastVisitedURL(request));
+			break;
+
+		case ACTION_CODE_GET_STATUS:
+			// get the XML document containing contents of the requested
+			// directory path
+			writeXMLToResponse(getIndexingStatus(), response, false);
+			break;
+
+		case ACTION_CODE_SET_INDEXING_PATH:
+			String path = request.getParameter(ACTION_PARAM_PATH);
+			if ((path == null) || (path.isEmpty())) {
+				response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE,
+						"Invalid path parameter specified!");
+				return;
+			}
+
+			// send the client back the to previous page
+			response.sendRedirect(Session.getLastVisitedURL(request));
+			break;
+
+		case ACTION_CODE_SET_ADVANCED_SETTINGS:
+			HashMap<String, String[]> advSettings = new HashMap<String, String[]>();
+
+			// get all the settings and their values
+			Enumeration<String> params = request.getParameterNames();
+			while (params.hasMoreElements()) {
+				String name = params.nextElement();
+				// ignore the main params (the ones that go us here)
+				if (name.equalsIgnoreCase(PARAM_ACTION))
+					continue;
+				String[] value = request.getParameterValues(name);
+				advSettings.put(name, value);
+			}
+
+			// HashMap<String, Object> settings = idx.getSettings();
+			// Services svcs = Services.getInstance();
+			// svcs.processAdvancedSettings(settings, advSettings);
+
+			// try to apply the settings
+			/*
+			 * if (idx.trySettings(settings)){ idx.setSettings(settings);
+			 * svcs.saveSettings(); // send the client back the to previous page
+			 * response.sendRedirect(Session.getLastVisitedURL(request)); } else
+			 */
+			response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+					"Invalid parameters!");
+			break;
+
+		case ACTION_CODE_GET_PATH_CONTENTS:
+			path = request.getParameter(ACTION_PARAM_PATH);
+
+			// get the XML document containing contents of the requested
+			// directory path
+			writeXMLToResponse(getPathContents(path), response, false);
+			break;
+
+		default:
+			response.sendError(HttpServletResponse.SC_BAD_REQUEST,
+					"Invalid action!");
+			return;
+		}
+	}
+
+	/**
+	 * Based on the request, returns a String containing a form with all the
+	 * settings inputs boxes. These boxes are rendered/specified in accordance
+	 * with the each setting value type reported by the plugin/service.
+	 * 
+	 * @param request
+	 *            the servlet request object.
+	 * @param brokerURL
+	 *            the URL of the broker that will apply the settings after
+	 *            receiving this forms post.
+	 * @param elementID
+	 *            the ID of this HTML form, can be null.
+	 * @return a String containing the HTML structure for the form with all the
+	 *         plugin advanced setting.
+	 */
+	public static String getHTMLServiceAdvancedSettingsForm(
+			HttpServletRequest request, String brokerURL, String elementID)
+			throws IOException {
+		String result = "";
+
+		if ((elementID == null) || elementID.trim().isEmpty())
+			result += "<form ";
+		else
+			result += "<form id=\"" + elementID + "\" ";
+		result += "action=\"" + brokerURL + "\" method=\"get\">";
+
+		result += "<input type=\"hidden\" name=\"" + PARAM_ACTION
+				+ "\" value=\"" + ACTION_SET_ADVANCED_SETTINGS + "\" />";
+
+		result += "<table class=\"table table-hover\"><tbody>";
+
+		// HashMap<String, Object> settings = idx.getSettings();
+		// HashMap<String, String> settingsHelp = idx.getSettingsHelp();
+
+		HashMap<String, Object> settings = new HashMap<>();
+		HashMap<String, String> settingsHelp = new HashMap<>();
+
+		Services svcs = Services.getInstance();
+
+		// create a table row for each setting (includes name, value/type and
+		// help, if available)
+		for (Map.Entry<String, Object> setting : settings.entrySet()) {
+			String key = setting.getKey();
+			Object value = setting.getValue();
+			String help = settingsHelp.get(key);
+
+			result += svcs.getHTMLAdvancedSettingsFormRow(key, value, help);
+		}
+
+		result += "</tbody></table><br />";
+		result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
+		result += "</form>";
+
+		return result;
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest request,
+			HttpServletResponse response) throws IOException {
+		doGet(request, response);
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/RestletHttpServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/RestletHttpServlet.java
new file mode 100644
index 0000000..e4624ab
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/RestletHttpServlet.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.restlet.Restlet;
+import org.restlet.ext.servlet.ServletAdapter;
+
+/** A servlet holding a Restlet.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class RestletHttpServlet extends HttpServlet {
+
+    private ServletAdapter adapter;
+    private final Restlet restlet;
+
+    public RestletHttpServlet(Restlet restlet) {
+        this.restlet = restlet;
+    }
+
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        this.adapter = new ServletAdapter(getServletContext());
+        this.restlet.setContext(this.adapter.getContext());
+        this.adapter.setNext(this.restlet);
+    }
+
+    @Override
+    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        this.adapter.service(req, resp);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SearchHolderServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SearchHolderServlet.java
new file mode 100644
index 0000000..0baddaf
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SearchHolderServlet.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.collections.KeyValue;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.core.dim.DIMGeneric;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.server.web.dicom.SearchHolder;
+import pt.ua.dicoogle.server.web.utils.DIM2JSONConverter;
+
+/**
+ * Useful servlet for asynchronous queries.
+ * 
+ * @author Tiago Godinho.
+ *
+ */
+public class SearchHolderServlet extends HttpServlet
+{
+	private static final long serialVersionUID = 1L;
+	
+	@Override
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+	{
+		HttpSession session = request.getSession(true);
+		if(session == null){
+			response.sendError(401, "ERROR: NO SESSION FOUND");
+			return;
+		}
+		SearchHolder holder = (SearchHolder) session.getAttribute("dicoogle.web.queryHolder");
+		if(holder == null){
+			response.sendError(402, "ERROR: NO SEARCH SESSION FOUND");
+			return;
+		}
+		int id = Integer.parseInt(request.getParameter("id"));
+
+		response.setHeader("pragma", "no-cache,no-store"); 
+		response.setHeader("cache-control", "no-cache,no-store,max-age=0,max-stale=0"); 
+		response.setHeader("connection", "keep-alive");
+		response.setContentType("text/event-stream"); 		
+		response.setCharacterEncoding("UTF-8"); // set the apropriate encoding type
+
+		PrintWriter wr = response.getWriter();
+
+		Iterable<KeyValue> it = holder.retrieveQueryOutput(id);
+
+		wr.print("data: \n\n"); 
+		wr.flush();
+
+		int eventID = 0;
+		for(KeyValue resp : it){
+			List<SearchResult> results = new ArrayList<>();
+			
+			String provider = resp.getKey().toString();
+			@SuppressWarnings("unchecked")
+			Iterable<SearchResult> result = (Iterable<SearchResult>) resp.getValue();
+			for(SearchResult r : result )
+				results.add(r);
+			
+			try {
+				DIMGeneric generic = new DIMGeneric(results);
+				
+				JSONObject obj = new JSONObject();
+				obj.put("provider", provider);
+				JSONArray arr = DIM2JSONConverter.convertToJSON(generic);		
+				obj.put("rsp", arr);
+				
+				wr.print("id: "+ (eventID++)+"\n");
+				wr.print("event: QueryResponse\n"); 
+				wr.print("data: "+obj.toString()+"\n\n"); 
+				wr.flush();
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+		}
+		wr.print("event: close\n");
+		wr.flush();
+		wr.close();
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SettingsServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SettingsServlet.java
new file mode 100644
index 0000000..461d749
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/SettingsServlet.java
@@ -0,0 +1,423 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Enumeration;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONException;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.core.XMLSupport;
+import pt.ua.dicoogle.server.web.management.Dicoogle;
+import pt.ua.dicoogle.server.web.management.Services;
+import pt.ua.dicoogle.server.web.auth.Session;
+import static pt.ua.dicoogle.sdk.settings.Utils.processAdvancedSettings;
+
+/**
+ * Handles requests for applying the general/advanced Dicoogle Settings.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+ at Deprecated
+public class SettingsServlet extends HttpServlet
+{
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	private static Dicoogle dic;
+
+	public static final String PARAM_ACTION = "action";
+
+	public static final String ACTION_SET_ADVANCED_SETTINGS = "setadvancedsettings";
+	public static final String ACTION_SET_ACCESS_LIST_SETTINGS = "setaccesslistsettings";
+	public static final String ACTION_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS = "settransferstorageglobalsettings";
+	public static final String ACTION_SET_STORAGE_SERVICES = "setstorageservices";
+
+	/*
+	 * Action codes for internal use.
+	 */
+	private static final int ACTION_CODE_INVALID = 0;
+	private static final int ACTION_CODE_SET_ADVANCED_SETTINGS = 1;
+	private static final int ACTION_CODE_SET_ACCESS_LIST_SETTINGS = 2;
+	private static final int ACTION_CODE_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS = 3;
+	private static final int ACTION_CODE_SET_STORAGE_SERVICES = 4;
+
+	public SettingsServlet()
+	{
+		dic = Dicoogle.getInstance();
+	}
+
+	@Override
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
+	{
+		// TODO validate user session credentials
+
+		// get which action to take
+		String actionStr = request.getParameter(PARAM_ACTION);
+
+		// translate each action string to a action identification
+		int action = ACTION_CODE_INVALID;
+		if (actionStr != null)
+		{
+			if (actionStr.equalsIgnoreCase(ACTION_SET_ADVANCED_SETTINGS))
+				action = ACTION_CODE_SET_ADVANCED_SETTINGS;
+			else if (actionStr.equalsIgnoreCase(ACTION_SET_ACCESS_LIST_SETTINGS))
+				action = ACTION_CODE_SET_ACCESS_LIST_SETTINGS;
+			else if (actionStr.equalsIgnoreCase(ACTION_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS))
+				action = ACTION_CODE_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS;
+			else if (actionStr.equalsIgnoreCase(ACTION_SET_STORAGE_SERVICES))
+				action = ACTION_CODE_SET_STORAGE_SERVICES;
+
+		}
+
+		// response to each action accordingly
+		switch (action)
+		{
+			case ACTION_CODE_SET_ADVANCED_SETTINGS:
+				HashMap<String, String[]> advSettings = new HashMap<String, String[]>();
+
+				// get all the settings and their values
+				Enumeration<String> params = request.getParameterNames();
+				while (params.hasMoreElements())
+				{
+					String name = params.nextElement();
+
+					// ignore the main params (the ones that go us here)
+					if (name.equalsIgnoreCase(PARAM_ACTION))
+						continue;
+
+					String[] value = request.getParameterValues(name);
+					advSettings.put(name, value);
+				}
+
+				HashMap<String, Object> settings = dic.getIndexingSettings();
+
+				processAdvancedSettings(settings, advSettings);
+
+				// try to apply the settings
+				if (dic.tryIndexingSettings(settings))
+				{
+					dic.setIndexingSettings(settings);
+
+					Services svcs = Services.getInstance();
+					svcs.saveSettings();
+
+					// send	the client back the to previous page
+					response.sendRedirect(Session.getLastVisitedURL(request));
+				}
+				else
+					response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameters!");
+			break;
+
+			case ACTION_CODE_SET_ACCESS_LIST_SETTINGS:
+				advSettings = new HashMap<String, String[]>();
+
+				// get all the settings and their values
+				params = request.getParameterNames();
+				while (params.hasMoreElements())
+				{
+					String name = params.nextElement();
+
+					// ignore the main params (the ones that go us here)
+					if (name.equalsIgnoreCase(PARAM_ACTION))
+						continue;
+
+					String[] value = request.getParameterValues(name);
+
+					advSettings.put(name, value);
+				}
+
+				settings = dic.getAccessListSettings();
+
+				processAdvancedSettings(settings, advSettings);
+
+				// try to apply the settings
+				if (dic.tryAccessListSettings(settings))
+				{
+					dic.setAccessListSettings(settings);
+
+					Services svcs = Services.getInstance();
+					svcs.saveSettings();
+					// TODO force the reload of the IAccessList implementation for the RMI interface
+
+					// send	the client back the to previous page
+					response.sendRedirect(Session.getLastVisitedURL(request));
+				}
+				else
+					response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameters!");
+			break;
+
+			case ACTION_CODE_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS:
+				advSettings = new HashMap<String, String[]>();
+
+				// get all the settings and their values
+				params = request.getParameterNames();
+				while (params.hasMoreElements())
+				{
+					String name = params.nextElement();
+
+					// ignore the main params (the ones that go us here)
+					if (name.equalsIgnoreCase(PARAM_ACTION))
+						continue;
+
+					String[] value = request.getParameterValues(name);
+
+					advSettings.put(name, value);
+				}
+
+				settings = dic.getSOPClassGlobalSettings();
+
+				processAdvancedSettings(settings, advSettings);
+
+				// try to apply the settings
+				if (dic.trySOPClassGlobalSettings(settings))
+				{
+					dic.setSOPClassGlobalSettings(settings);
+
+					Services svcs = Services.getInstance();
+					svcs.saveSettings();
+
+					// send	the client back the to previous page
+					response.sendRedirect(Session.getLastVisitedURL(request));
+				}
+				else
+					response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid parameters!");
+			break;
+			
+			case ACTION_CODE_SET_STORAGE_SERVICES:
+
+				String requestParam = request.getParameter("MOVES");
+
+				if(requestParam == null){
+					response.sendError(401,"No Moves Defined");
+					return;
+				}
+				
+				ServerSettings set = ServerSettings.getInstance();
+				ArrayList<MoveDestination> nmoves = new ArrayList<MoveDestination>();
+				
+				JSONArray moves = JSONArray.fromObject(requestParam);
+				Iterator it = moves.iterator();
+				while(it.hasNext()){
+					JSONObject obj = (JSONObject) it.next();
+					
+					try{
+						String aet = obj.getString("AETitle");
+						String ip = obj.getString("ipAddrs");
+						int port = obj.getInt("port");
+						
+						if( StringUtils.isNotBlank(aet) && StringUtils.isNotBlank(ip) && port > 0){
+							nmoves.add(new MoveDestination(aet, ip, port));	
+						}	
+					}catch(JSONException ex){
+						
+					}			
+				}
+				
+				set.setMoves(nmoves);
+				
+				XMLSupport _xml = new XMLSupport();
+				_xml.printXML();
+				_xml = null;
+				
+				break;
+
+			default:
+				response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid action!");
+				return;
+		}
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException
+	{
+		doGet(request, response);
+	}
+
+	/**
+	 * Based on the request, returns a String containing a form with all the settings inputs boxes regarding the indexing options.
+	 * These boxes are rendered/specified in accordance with the each setting value type reported by the plugin/service.
+	 *
+	 * @param request the servlet request object.
+	 * @param brokerURL the URL of the broker that will apply the settings after receiving this forms post.
+	 * @param elementID the ID of this HTML form, can be null.
+	 * @return a String containing the HTML structure for the form with all the settings.
+	 */
+	public static String getHTMLIndexingAdvancedSettingsForm(HttpServletRequest request, String brokerURL, String elementID) throws IOException
+	{
+		String result = "";
+
+		if ((elementID == null) || elementID.trim().isEmpty())
+			result += "<form ";
+		else
+			result += "<form id=\"" + elementID + "\" ";
+		result += "action=\"" + brokerURL + "\" method=\"get\">";
+
+		result += "<input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_SET_ADVANCED_SETTINGS + "\" />";
+
+		result += "<table class=\"table table-hover\"><tbody>";
+
+		HashMap<String, Object> settings = dic.getIndexingSettings();
+		HashMap<String, String> settingsHelp = dic.getIndexingSettingsHelp();
+
+		Services svcs = Services.getInstance();
+
+		// just to avoid any unwanted exceptions, in case a plugin misbehaves
+		if (settings == null)
+			settings = new HashMap<String, Object>();
+		if (settingsHelp == null)
+			settingsHelp = new HashMap<String, String>();
+
+		// create a table row for each setting (includes name, value/type and help, if available)
+		for (Map.Entry<String, Object> setting : settings.entrySet())
+		{
+			String key = setting.getKey();
+			Object value = setting.getValue();
+			String help = settingsHelp.get(key);
+
+			result += svcs.getHTMLAdvancedSettingsFormRow(key, value, help);
+		}
+
+		result += "</tbody></table><br />";
+
+		result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
+		result += "</form>";
+
+		return result;
+	}
+
+	/**
+	 * Based on the request, returns a String containing a form with all the settings inputs boxes regarding the Dicoogle Access List settings.
+	 * These boxes are rendered/specified in accordance with the each setting value type reported by the plugin/service.
+	 *
+	 * @param request the servlet request object.
+	 * @param brokerURL the URL of the broker that will apply the settings after receiving this forms post.
+	 * @param elementID the ID of this HTML form, can be null.
+	 * @return a String containing the HTML structure for the form with all the settings.
+	 */
+	public static String getHTMLAccessListSettingsForm(HttpServletRequest request, String brokerURL, String elementID) throws IOException
+	{
+		String result = "";
+
+		if ((elementID == null) || elementID.trim().isEmpty())
+			result += "<form ";
+		else
+			result += "<form id=\"" + elementID + "\" ";
+		result += "action=\"" + brokerURL + "\" method=\"get\">";
+
+		result += "<input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_SET_ACCESS_LIST_SETTINGS + "\" />";
+
+		result += "<table class=\"table table-hover\"><tbody>";
+
+		HashMap<String, Object> settings = dic.getAccessListSettings();
+		HashMap<String, String> settingsHelp = dic.getAccessListSettingsHelp();
+
+		Services svcs = Services.getInstance();
+
+		// just to avoid any unwanted exceptions, in case a plugin misbehaves
+		if (settings == null)
+			settings = new HashMap<String, Object>();
+		if (settingsHelp == null)
+			settingsHelp = new HashMap<String, String>();
+
+		// create a table row for each setting (includes name, value/type and help, if available)
+		for (Map.Entry<String, Object> setting : settings.entrySet())
+		{
+			String key = setting.getKey();
+			Object value = setting.getValue();
+			String help = settingsHelp.get(key);
+
+			result += svcs.getHTMLAdvancedSettingsFormRow(key, value, help);
+		}
+
+		result += "</tbody></table><br />";
+
+		result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
+		result += "</form>";
+
+		return result;
+	}
+
+	/**
+	 * Based on the request, returns a String containing a form with all the settings inputs boxes regarding the Dicoogle Global SOP Classes Transfer Storage settings.
+	 * These boxes are rendered/specified in accordance with the each setting value type reported by the plugin/service.
+	 *
+	 * @param request the servlet request object.
+	 * @param brokerURL the URL of the broker that will apply the settings after receiving this forms post.
+	 * @param elementID the ID of this HTML form, can be null.
+	 * @return a String containing the HTML structure for the form with all the settings.
+	 */
+	public static String getHTMLGlobalTransferStorageSettingsForm(HttpServletRequest request, String brokerURL, String elementID) throws IOException
+	{
+		String result = "";
+
+		if ((elementID == null) || elementID.trim().isEmpty())
+			result += "<form ";
+		else
+			result += "<form id=\"" + elementID + "\" ";
+		result += "action=\"" + brokerURL + "\" method=\"get\">";
+
+		result += "<input type=\"hidden\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_SET_SOP_CLASS_GLOBAL_TRANSFER_STORAGE_SETTINGS + "\" />";
+
+		result += "<table class=\"table table-condensed\"><tbody>";
+		
+		HashMap<String, Object> settings = dic.getSOPClassGlobalSettings();
+		HashMap<String, String> settingsHelp = dic.getSOPClassGlobalSettingsHelp();
+
+		Services svcs = Services.getInstance();
+
+		// just to avoid any unwanted exceptions, in case a plugin misbehaves
+		if (settings == null)
+			settings = new HashMap<String, Object>();
+		if (settingsHelp == null)
+			settingsHelp = new HashMap<String, String>();
+
+		// create a table row for each setting (includes name, value/type and help, if available)
+		for (Map.Entry<String, Object> setting : settings.entrySet())
+		{
+			String key = setting.getKey();
+			Object value = setting.getValue();
+			String help = settingsHelp.get(key);
+			
+			result += svcs.getHTMLAdvancedSettingsFormRow(key, value, help);
+		}
+		
+		result += "</tbody></table><br />";
+
+		result += "<input type=\"submit\" value=\"Apply Settings\" class=\"btn btn-primary\"/>";
+		result += "</form>";
+
+		return result;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/TagsServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/TagsServlet.java
new file mode 100644
index 0000000..5b3a5a0
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/TagsServlet.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import javax.servlet.ServletOutputStream;
+import pt.ua.dicoogle.server.web.dicom.Information;
+
+/**
+ * Handles the requests for DICOM file tags information, returning the information as a XML document.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class TagsServlet extends HttpServlet
+{
+	@Override
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+	{
+		String sopInstanceUID = request.getParameter("SOPInstanceUID");
+		if (sopInstanceUID == null || sopInstanceUID.trim().isEmpty()) // make sure that the SOPInstanceUID param is supplied
+		{
+			response.sendError(400, "Invalid SOP Instance UID!");
+			return;
+		}
+        
+        String[] providerArray = request.getParameterValues("provider");
+        List<String> providers = providerArray == null ? null : Arrays.asList(providerArray);
+
+		// get the XML document containing the tags for that SOP Instance UID file
+		String xml = Information.getXMLTagListFromFile(sopInstanceUID, providers);
+
+		// if no xml was retrieved, tell the client
+		if (xml == null)
+		{
+			response.sendError(404, "SOP Instance UID not indexed/found!");
+			return;
+		}
+
+		// get the returned xml as a UTF-8 byte array
+		byte[] data = xml.getBytes("UTF-8");
+		if (data == null)
+		{
+			response.sendError(500, "Could generate the resulting XML document!");
+			return;
+		}
+
+		response.setContentType("application/xml"); // set the appropriate type for the XML file
+		response.setContentLength(data.length); // set the document size
+		//response.setCharacterEncoding("UTF-8"); // set the apropriate encoding type
+
+		// write the XML data to the response output
+		ServletOutputStream out = response.getOutputStream();
+		out.write(data);
+		out.close();
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LoginServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LoginServlet.java
new file mode 100644
index 0000000..debe84d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LoginServlet.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.accounts;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.server.users.Role;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UsersStruct;
+import pt.ua.dicoogle.server.web.auth.LoggedIn;
+import pt.ua.dicoogle.server.web.auth.LoggedInStatus;
+import pt.ua.dicoogle.server.web.auth.Session;
+
+/**
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class LoginServlet extends HttpServlet {
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //Try login
+        // Does not require admin rights.
+        LoggedInStatus loginStatus = Session.webappLogin(req, resp, false);
+        LoggedIn mLoggedIn = loginStatus.getLogin();
+
+        if (mLoggedIn == null) {
+            resp.sendError(401, "Login failed");
+            return;
+        }
+
+        JSONObject json_resp = new JSONObject();
+        json_resp.put("user", mLoggedIn.getUserName());
+        json_resp.put("admin", mLoggedIn.isAdmin());
+        User u = UsersStruct.getInstance().getUser(mLoggedIn.getUserName());
+        JSONArray rolesObj = new JSONArray();
+        if (u!=null&&u.getRoles()!=null) {
+            for (Role r : u.getRoles()) {
+                if (r!=null)
+                    rolesObj.add(r.getName());
+            }
+
+            json_resp.put("roles", rolesObj);
+        }
+        json_resp.put("token", mLoggedIn.getToken());
+
+        //Set response content type
+        resp.setContentType("application/json");
+
+        //Write response
+        json_resp.write(resp.getWriter());
+    }
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+        //resp.addHeader("Access-Control-Allow-Origin", "*");
+		HttpSession session = req.getSession(false);
+		
+		LoggedIn mLoggedIn = Session.getUserLoggedIn(session);
+		if(mLoggedIn == null){
+			resp.sendError(401);
+            return;
+		}
+			
+		JSONObject json_resp = new JSONObject();
+        json_resp.put("user", mLoggedIn.getUserName());
+        json_resp.put("admin", mLoggedIn.isAdmin());
+        User u = UsersStruct.getInstance().getUser(mLoggedIn.getUserName());
+        JSONArray rolesObj = new JSONArray();
+        for (Role r : u.getRoles())
+        {
+            rolesObj.add(r.getName());
+        }
+
+        json_resp.put("roles", rolesObj);
+
+        //Set response content type
+        resp.setContentType("application/json");
+
+        //Write response
+        json_resp.write(resp.getWriter());
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LogoutServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LogoutServlet.java
new file mode 100644
index 0000000..c18c278
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/LogoutServlet.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.accounts;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import pt.ua.dicoogle.server.web.auth.Authentication;
+import pt.ua.dicoogle.server.web.auth.Session;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+
+/**
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class LogoutServlet extends HttpServlet{
+    
+    private static final String TOKEN_HEADERNAME = "Authorization";
+
+    @Deprecated
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        this.doPost(req, resp);
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        boolean logout = Session.logout(req);
+        String token = req.getHeader(TOKEN_HEADERNAME);
+        if (token != null && !token.equals("")) {
+            Authentication.getInstance().logout(token);
+        }
+        ResponseUtil.simpleResponse(resp,"success", logout);
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/UserServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/UserServlet.java
new file mode 100644
index 0000000..6646183
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/accounts/UserServlet.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.accounts;
+
+import java.io.IOException;
+import java.util.Set;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import pt.ua.dicoogle.server.users.HashService;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UsersStruct;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+
+/**
+ * User Servlet for create, remove and consult user accounts
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class UserServlet extends HttpServlet {
+
+    @Override
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String usernameToRemove = req.getParameter("username");
+
+        boolean isRemoved = false;
+        if (usernameToRemove != null && !usernameToRemove.equals("")) {
+            isRemoved = UsersStruct.getInstance().removeUser(usernameToRemove);
+        }
+
+        ResponseUtil.simpleResponse(resp, "success",isRemoved);
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String user = req.getParameter("username");
+        String pass = req.getParameter("password");
+        boolean admin = Boolean.parseBoolean(req.getParameter("admin"));
+        //System.out.println("ADD USER: " + user + "\npass: " + pass + "\nadmin: " + admin);
+
+        String passHash = HashService.getSHA1Hash(pass);             //password Hash
+        String Hash = HashService.getSHA1Hash(user + admin + passHash);   //user Hash
+
+        boolean wasAdded = UsersStruct.getInstance().addUser(new User(user, Hash, admin));
+        ResponseUtil.simpleResponse(resp, "success",wasAdded );
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        Set<String> users = UsersStruct.getInstance().getUsernames();
+        resp.setContentType("application/json");
+        
+        JSONObject jsonObject = new JSONObject();
+        JSONArray usersArray = new JSONArray();
+        for (String user : users) {
+            JSONObject u = new JSONObject();
+            u.put("username", user);
+            usersArray.add(u);
+        }
+
+        jsonObject.put("users", usersArray);
+        jsonObject.write(resp.getWriter());
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/AETitleServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/AETitleServlet.java
new file mode 100644
index 0000000..8d638c9
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/AETitleServlet.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil.Pair;
+
+/**
+ * 
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class AETitleServlet extends HttpServlet{
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		List<Pair> mpairs = new ArrayList<>();
+		mpairs.add(new ResponseUtil.Pair("aetitle", ServerSettings.getInstance().getAE()));
+		
+		ResponseUtil.objectResponse(resp, mpairs);
+	}
+
+	@Override
+	protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		String aetitle = req.getParameter("aetitle");
+		
+		if(StringUtils.isEmpty(aetitle))
+		{
+			resp.sendError(402, "aetitle param not found");
+			return;
+		}
+		
+		ServerSettings.getInstance().setAE(aetitle);
+		
+		ResponseUtil.simpleResponse(resp, "success", true);
+		
+	}
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/DicomQuerySettingsServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/DicomQuerySettingsServlet.java
new file mode 100644
index 0000000..62a0852
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/DicomQuerySettingsServlet.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSONSerializer;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.core.ServerSettings;
+
+/**
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class DicomQuerySettingsServlet extends HttpServlet {
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		ServerSettings ss = ServerSettings.getInstance();
+
+		int responseTimeout = ss.getRspDelay();
+		int connectionTimeout = ss.getConnectionTimeout();
+		int idleTimeout = ss.getIdleTimeout();
+		int acceptTimeout = ss.getAcceptTimeout();
+		int maxPduSend = ss.getMaxPDULenghtSend();
+		int maxPduReceive = ss.getMaxPDULengthReceive();
+		int maxAssociations = ss.getMaxClientAssoc();
+
+		QueryRetrieveSettingsObject queryRetrieveSettings = new QueryRetrieveSettingsObject(
+				responseTimeout, connectionTimeout, idleTimeout, acceptTimeout,
+				maxPduSend, maxPduReceive, maxAssociations);
+        	resp.setContentType("application/json");
+		resp.getWriter().write(JSONSerializer.toJSON(queryRetrieveSettings).toString());
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		String responseTimeout = req.getParameter("responseTimeout");
+		String connectionTimeout = req.getParameter("connectionTimeout");
+		String idleTimeout = req.getParameter("idleTimeout");
+		String acceptTimeout = req.getParameter("acceptTimeout");
+		String maxPduSend = req.getParameter("maxPduSend");
+		String maxPduReceive = req.getParameter("maxPduReceive");
+		String maxAssociations = req.getParameter("maxAssociations");
+
+		ServerSettings ss = ServerSettings.getInstance();
+
+		if (StringUtils.isNotEmpty(responseTimeout)) {
+			int intV = Integer.parseInt(responseTimeout);
+			ss.setRspDelay(intV);
+		}
+		if (StringUtils.isNotEmpty(connectionTimeout)) {
+			int intV = Integer.parseInt(connectionTimeout);
+			ss.setConnectionTimeout(intV);
+		}
+		if (StringUtils.isNotEmpty(idleTimeout)) {
+			int intV = Integer.parseInt(idleTimeout);
+			ss.setIdleTimeout(intV);
+		}
+		if (StringUtils.isNotEmpty(acceptTimeout)) {
+			int intV = Integer.parseInt(acceptTimeout);
+			ss.setAcceptTimeout(intV);
+		}
+		if (StringUtils.isNotEmpty(maxPduSend)) {
+			int intV = Integer.parseInt(maxPduSend);
+			ss.setMaxPDULengthSend(intV);
+		}
+		if (StringUtils.isNotEmpty(maxPduReceive)) {
+			int intV = Integer.parseInt(maxPduReceive);
+			ss.setMaxPDULengthReceive(intV);
+		}
+		if (StringUtils.isNotEmpty(maxAssociations)) {
+			int intV = Integer.parseInt(maxAssociations);
+			ss.setMaxClientAssoc(intV);
+		}
+
+	}
+
+	/*
+	 * MODEL FOR QUERY RETRIEVE SETTINGS
+	 */
+	public static class QueryRetrieveSettingsObject {
+        private int responseTimeout, connectionTimeout, idleTimeout, acceptTimeout,
+				maxPduSend, maxPduReceive, maxAssociations;
+
+        public QueryRetrieveSettingsObject() {
+        }
+        
+		public QueryRetrieveSettingsObject(int responseTimeout,
+				int connectionTimeout, int idleTimeout, int acceptTimeout,
+				int maxPduSend, int maxPduReceive, int maxAssociations) {
+			super();
+			this.responseTimeout = responseTimeout;
+			this.connectionTimeout = connectionTimeout;
+			this.idleTimeout = idleTimeout;
+			this.acceptTimeout = acceptTimeout;
+			this.maxPduSend = maxPduSend;
+			this.maxPduReceive = maxPduReceive;
+			this.maxAssociations = maxAssociations;
+		}
+
+        public int getResponseTimeout() {
+            return responseTimeout;
+        }
+
+        public void setResponseTimeout(int responseTimeout) {
+            this.responseTimeout = responseTimeout;
+        }
+
+        public int getConnectionTimeout() {
+            return connectionTimeout;
+        }
+
+        public void setConnectionTimeout(int connectionTimeout) {
+            this.connectionTimeout = connectionTimeout;
+        }
+
+        public int getIdleTimeout() {
+            return idleTimeout;
+        }
+
+        public void setIdleTimeout(int idleTimeout) {
+            this.idleTimeout = idleTimeout;
+        }
+
+        public int getAcceptTimeout() {
+            return acceptTimeout;
+        }
+
+        public void setAcceptTimeout(int acceptTimeout) {
+            this.acceptTimeout = acceptTimeout;
+        }
+
+        public int getMaxPduSend() {
+            return maxPduSend;
+        }
+
+        public void setMaxPduSend(int maxPduSend) {
+            this.maxPduSend = maxPduSend;
+        }
+
+        public int getMaxPduReceive() {
+            return maxPduReceive;
+        }
+
+        public void setMaxPduReceive(int maxPduReceive) {
+            this.maxPduReceive = maxPduReceive;
+        }
+
+        public int getMaxAssociations() {
+            return maxAssociations;
+        }
+
+        public void setMaxAssociations(int maxAssociations) {
+            this.maxAssociations = maxAssociations;
+        }
+
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ForceIndexing.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ForceIndexing.java
new file mode 100644
index 0000000..08e6e86
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ForceIndexing.java
@@ -0,0 +1,155 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.IndexReport;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class ForceIndexing extends HttpServlet {
+    
+    private static final Logger logger = LoggerFactory.getLogger(ForceIndexing.class);
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  @Override
+  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
+      IOException {
+
+    // Getting Parameters.
+    String[] uris = req.getParameterValues("uri");
+    String[] pluginsName = req.getParameterValues("plugin");
+
+    if (uris == null) {
+      resp.sendError(400, "No uri provided");
+      return;
+    }
+
+    final PluginController pc = PluginController.getInstance();
+
+    int expectedReports = uris.length * ((pluginsName == null) ?
+            pc.getIndexingPlugins(true).size() :
+            pluginsName.length);
+    
+    //Firing Tasks.
+    List<Task<Report>> reports = new ArrayList<>(expectedReports);
+    for (String uri : uris) {
+        try {
+            URI u = new URI(uri.replaceAll(" ", "%20"));
+            // log.info("Sent Index Request: {}, {}",pluginName, u.toString());
+            if (pluginsName == null) {
+              reports.addAll(pc.index(u));
+            } else {
+              for (String pluginName : pluginsName) {
+                reports.addAll(pc.index(pluginName, u));
+              }
+            }
+        } catch (URISyntaxException ex) {
+            logger.debug("Client provided bad URI");
+            resp.sendError(400);
+            return;
+        }
+    }
+
+    // waiting is bad, clearing all this and giving an ok
+    resp.setStatus(200);
+    
+    /*
+    //Waiting for results, construct the output.
+    List<Report> done = new ArrayList<>(reports.size());
+    JSONArray ret = new JSONArray();
+    for (Task<Report> t : reports) {
+      try {
+        Report report = t.get();
+        done.add(report);
+        JSONObject obj;
+        if (report instanceof IndexReport) {
+            IndexReport indexReport = (IndexReport) report;
+            obj = convertReportToJSON(indexReport);
+        } else {
+            // no information is available
+            obj = new JSONObject();
+            obj.put("complete", true);
+            obj.put("errors", 0);
+        }
+        ret.add(obj);
+      } catch (InterruptedException | ExecutionException ex) {
+        // log.error("UNKNOW ERROR", ex);
+      }
+    }
+    // log.info("Finished forced indexing procedure: {}", reports.size());
+
+    resp.setContentType("application/json");
+    resp.getWriter().write(ret.toString());
+    resp.getWriter().flush();
+    */
+  }
+  
+  @Deprecated
+  private static JSONObject convertReportToJSON(IndexReport r){
+    JSONObject obj = new JSONObject();
+    obj.put("indexed", r.getNIndexed());
+    obj.put("errors", r.getNErrors());
+    obj.put("elapsedTime", r.getElapsedTime());
+    
+    JSONObject extraObjects = new JSONObject();
+    
+    Method[] methods = r.getClass().getDeclaredMethods();
+    for(Method m : methods){
+      if( Modifier.isPublic(m.getModifiers()) && m.getName().startsWith("get") && m.getParameterTypes().length == 0){
+        Object ret = null;
+        try {
+          ret = m.invoke(r, null);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+        }
+        if(ret != null)
+          extraObjects.put(m.getName().substring(3), ret);
+      }
+    }    
+    
+    obj.put("extra", extraObjects);
+    return obj;
+  }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/IndexerSettingsServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/IndexerSettingsServlet.java
new file mode 100644
index 0000000..efe198b
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/IndexerSettingsServlet.java
@@ -0,0 +1,158 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.core.XMLSupport;
+
+/**
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class IndexerSettingsServlet extends HttpServlet {
+
+    public enum SettingsType {
+
+        all,path, zip, effort, thumbnail,thumbnailSize, watcher;
+    }
+    private final SettingsType type;
+
+    public IndexerSettingsServlet(SettingsType type) {
+        this.type = type;
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+    	
+    	String param = null;
+    	String path = null;
+    	boolean watcher=false, zip = false, saveT = false;
+    	int ieffort = 0;
+    	String tumbnailSize = null;
+    	if(type != SettingsType.all)
+    	{
+    		param = req.getParameter(type.toString());
+    	
+    		if (StringUtils.isEmpty(param)) {
+                resp.sendError(400, "Invalid " + type.toString());
+            }
+    	}
+    	else{
+    		path = req.getParameter("path");
+    		watcher = Boolean.parseBoolean(req.getParameter("watcher"));
+    		zip = Boolean.parseBoolean(req.getParameter("zip"));
+    		saveT = Boolean.parseBoolean(req.getParameter("saveThumbnail"));
+    		ieffort = Integer.parseInt(req.getParameter("effort"));
+    		tumbnailSize = req.getParameter("thumbnailSize");
+    	}
+
+        switch (type) {
+            case path:
+                ServerSettings.getInstance().setDicoogleDir(param);
+                resp.getWriter().append("Dir set to: " + param);
+                break;
+            case zip:
+                boolean gzip = Boolean.parseBoolean(param);
+                ServerSettings.getInstance().setGzipStorage(gzip);
+                resp.getWriter().append("Storage/Index Files compressed  set to: " + param);
+                break;
+            case effort:
+                //TODO: CHECK ACCPTABLE RANGE
+                int effort = Integer.parseInt(param);
+                ServerSettings.getInstance().setIndexerEffort(effort);
+                resp.getWriter().append("index effort set to: " + effort);
+                break;
+            case thumbnail:
+            	boolean saveThumbanail = Boolean.parseBoolean(param);
+            	ServerSettings.getInstance().setSaveThumbnails(saveThumbanail);
+            	break;
+            case thumbnailSize:
+            	//TODO: Should be a int
+            	//int thumbSize = Integer.parseInt(param);
+            	ServerSettings.getInstance().setThumbnailsMatrix(param);
+            	break;
+            case watcher:
+            	ServerSettings.getInstance().setMonitorWatcher(Boolean.parseBoolean(param));
+            	break;
+            case all:
+            	 ServerSettings.getInstance().setDicoogleDir(path);
+            	 ServerSettings.getInstance().setGzipStorage(zip);
+            	 ServerSettings.getInstance().setIndexerEffort(ieffort);
+            	 ServerSettings.getInstance().setSaveThumbnails(saveT);
+            	 ServerSettings.getInstance().setThumbnailsMatrix(tumbnailSize);
+            	 ServerSettings.getInstance().setMonitorWatcher(watcher);
+            	break;
+            	
+        }
+        new XMLSupport().printXML();
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String result = "";
+        resp.setContentType("application/json");
+        switch (type) {
+            case path:
+                result = ServerSettings.getInstance().getDicoogleDir();
+                break;
+            case zip:
+                result = String.valueOf(ServerSettings.getInstance().isGzipStorage());
+                break;
+            case effort:
+                result = String.valueOf(ServerSettings.getInstance().getIndexerEffort());
+                break;
+            case thumbnail:
+            	result = String.valueOf(ServerSettings.getInstance().getSaveThumbnails());
+            	break;
+            case thumbnailSize:
+            	result = String.valueOf(ServerSettings.getInstance().getThumbnailsMatrix());
+            	break;
+            case watcher:
+            	result = String.valueOf(ServerSettings.getInstance().isMonitorWatcher());
+            	break;
+            case all:
+            	JSONObject allresponse = new JSONObject();
+            	allresponse.put("path", ServerSettings.getInstance().getDicoogleDir());
+            	allresponse.put("zip", ServerSettings.getInstance().isGzipStorage());
+            	allresponse.put("effort", String.valueOf(ServerSettings.getInstance().getIndexerEffort()));
+            	allresponse.put("thumbnail", ServerSettings.getInstance().getSaveThumbnails());
+            	allresponse.put("thumbnailSize", String.valueOf(ServerSettings.getInstance().getThumbnailsMatrix()));
+            	allresponse.put("watcher", ServerSettings.getInstance().isMonitorWatcher());
+            	
+            	resp.getWriter().write(allresponse.toString());
+            	break;
+        }
+
+        resp.setContentType("application/json");
+        resp.getWriter().append(result);
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/LoggerServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/LoggerServlet.java
new file mode 100644
index 0000000..28b8121
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/LoggerServlet.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.appender.RandomAccessFileAppender;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.Utils.Platform;
+
+/**
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class LoggerServlet extends HttpServlet {
+    private static final Logger classLogger = LoggerFactory.getLogger(LoggerServlet.class);
+
+    private String logFilename = null;
+    
+    protected String logFilename() {
+        if (this.logFilename == null) {
+            org.apache.logging.log4j.Logger logger = LogManager.getLogger();
+            Map<String, Appender> appenderMap = ((org.apache.logging.log4j.core.Logger) logger).getAppenders();
+            for (Map.Entry<String,Appender> e : appenderMap.entrySet()) {
+                String filename = null;
+                Appender appender = e.getValue();
+                if (appender instanceof FileAppender) {
+                    filename = ((FileAppender)appender).getFileName();
+                } else if (appender instanceof RollingFileAppender) {
+                    filename = ((RollingFileAppender)appender).getFileName();
+                } else if (appender instanceof RandomAccessFileAppender) {
+                    filename = ((RandomAccessFileAppender)appender).getFileName();
+                } else if (appender instanceof RollingRandomAccessFileAppender) {
+                    filename = ((RollingRandomAccessFileAppender)appender).getFileName();
+                }
+                if (filename != null) {
+                    classLogger.debug("Using \"{}\" as the file for the server log.", filename);
+                    this.logFilename = filename;
+                    return this.logFilename;
+                }
+            }
+            // no file appender found, use default DICOMLOG.log
+            classLogger.debug("No file appender found, using \"DICOMLOG.log\" as the default logger");
+            this.logFilename = Platform.homePath() + "DICOMLOG.log";
+        }
+        return this.logFilename;
+    }
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		try (BufferedReader fis = new BufferedReader(new FileReader(logFilename()))) {
+            PrintWriter respWriter = resp.getWriter();
+            String l;
+            while ((l = fis.readLine()) != null) {
+                respWriter.println(l);
+            }
+        }
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RemoveServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RemoveServlet.java
new file mode 100644
index 0000000..896ec0d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RemoveServlet.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.plugins.PluginController;
+
+/** Remove servlet.
+ * 
+ * @author Tiago Marques Godinho <tmgodinho at ua.pt>
+ */
+public class RemoveServlet extends HttpServlet {
+
+    private static final Logger logger = LoggerFactory.getLogger(RemoveServlet.class);
+    
+    /**
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        // Getting Parameters.
+        String[] uris = req.getParameterValues("uri");
+
+        if (uris == null) {
+            resp.sendError(400, "No uri provided");
+            return;
+        }
+
+        URI[] effUris = new URI[uris.length];
+        try {
+            for (int i = 0 ; i < effUris.length ; i++) {
+                effUris[i] = new URI(uris[i]);
+            }
+        } catch (URISyntaxException ex) {
+            logger.info("Received bad URI", ex);
+            resp.sendError(400, "Bad URI: " + ex.getInput());
+            return;
+        }
+
+        // unindex
+        for (URI uri : effUris) {
+            try {
+                PluginController.getInstance().remove(uri);
+            } catch (RuntimeException ex) {
+                logger.error(ex.getMessage(), ex);
+            }
+        }
+
+        logger.info("Finished removing {}", Arrays.asList(uris));
+        resp.setStatus(200);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RunningTasksServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RunningTasksServlet.java
new file mode 100644
index 0000000..eeb88dc
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/RunningTasksServlet.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+import pt.ua.dicoogle.taskManager.RunningIndexTasks;
+
+/**
+*
+* @author Frederico Silva<fredericosilva at ua.pt>
+*/
+public class RunningTasksServlet extends HttpServlet {
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		
+		resp.setContentType("application/json");
+		resp.getWriter().write(RunningIndexTasks.getInstance().toJson());
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		String action = req.getParameter("action");
+		
+		if(action != null && !action.equals("delete"))
+		{
+			resp.sendError(400, "action param needed: only delete is supported");
+		}
+		
+		String type = req.getParameter("type");
+		String taskUid = req.getParameter("uid");
+		if(type == null)
+		{
+			resp.sendError(400,"type param not existent");
+		}
+		if(type.equals("close"))
+			ResponseUtil.simpleResponse(resp, "removed", RunningIndexTasks.getInstance().removeTask(taskUid));
+		else if(type.equals("stop"))
+			ResponseUtil.simpleResponse(resp, "stopped", RunningIndexTasks.getInstance().stopTask(taskUid));
+		else
+			ResponseUtil.simpleResponse(resp, "error", true);
+	}
+	
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServerStorageServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServerStorageServlet.java
new file mode 100644
index 0000000..ced465d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServerStorageServlet.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import net.sf.json.JSONSerializer;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.core.XMLSupport;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+
+/**
+ * 
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class ServerStorageServlet extends HttpServlet{
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+        resp.setContentType("application/json");
+		resp.getWriter().write(JSONSerializer.toJSON(ServerSettings.getInstance().getMoves()).toString());
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		
+		String type = req.getParameter("type");
+
+		if (type == null) {
+			sendError(resp, 400, "Missing argument \"type\": must be either \"add\" or \"remove\"");
+			return;
+		}
+
+		String ip = req.getParameter("ip");
+		String aetitle = req.getParameter("aetitle");
+		String port = req.getParameter("port");
+		String description = req.getParameter("description");
+		String paramPublic = req.getParameter("public");
+		boolean isPublic = paramPublic.isEmpty() || Boolean.parseBoolean(paramPublic);
+
+		// validate
+		if (aetitle == null) {
+			sendError(resp, 400, "Missing argument \"aetitle\"");
+			return;
+		}
+
+		switch(type){
+		case "add": {
+
+			if (ip == null) {
+				sendError(resp, 400, "Missing argument \"ip\"");
+				return;
+ 			}
+
+			if (port == null) {
+				sendError(resp, 400, "Missing argument \"port\"");
+				return;
+			}
+			int _port = Integer.parseInt(port);
+			if (_port < 1 || _port > 65535) {
+				sendError(resp, 400, "Illegal argument \"port\": must be in network socket port range");
+				return;
+			}
+
+			ServerSettings.getInstance().add(new MoveDestination(aetitle, ip, _port, isPublic, description));
+			ResponseUtil.simpleResponse(resp, "added", true);
+			break;
+		}
+		case "remove": {
+			boolean removed = ServerSettings.getInstance().removeMoveDestination(aetitle);
+			ResponseUtil.simpleResponse(resp, "removed", removed);
+			break;
+		}
+		}
+		
+		  new XMLSupport().printXML();
+	}
+
+	private static void sendError(HttpServletResponse resp, int code, String message) throws IOException {
+		resp.setStatus(code);
+		resp.setContentType("application/json");
+		JSONObject obj = new JSONObject();
+		obj.put("error", message);
+		resp.getWriter().append(obj.toString());
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServicesServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServicesServlet.java
new file mode 100644
index 0000000..5b574a8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/ServicesServlet.java
@@ -0,0 +1,198 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSONObject;
+
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.server.ControlServices;
+import pt.ua.dicoogle.server.web.management.Services;
+
+/** Servlet for reading and writing DICOM service configurations.
+ * Modifying the "running" setting will trigger a start or a stop on the actual service.
+ *
+ * At the moment, applying settings to PLUGIN-type services is not implemented, resulting in a no-op.
+ * 
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class ServicesServlet extends HttpServlet {
+	
+	public final static int STORAGE = 0;
+	public final static int PLUGIN = 1;
+	public final static int QUERY = 2;
+	
+	private final int mType;
+	public ServicesServlet(int type) {
+		if (type < 0 || type > 2) {
+			throw new IllegalArgumentException("Bad service type, must be 0, 1 or 2");
+		}
+		mType = type;
+	}
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+
+		final ControlServices controlServices = ControlServices.getInstance();
+		final ServerSettings serverSettings = ServerSettings.getInstance();
+
+		boolean isRunning = false; 
+		int port = -1;
+        boolean autostart = false;
+		switch (mType) {
+		case STORAGE:
+			isRunning = controlServices.storageIsRunning();
+			port = serverSettings.getStoragePort();
+			autostart = serverSettings.isStorage();
+			break;
+		case QUERY:
+			isRunning = controlServices.queryRetrieveIsRunning();
+			port = serverSettings.getWlsPort();
+			autostart = serverSettings.isQueryRetrive();
+			break;
+
+		default:
+			break;
+		}
+		
+        JSONObject obj = new JSONObject();
+        obj.element("isRunning", isRunning);
+        obj.element("port", port);
+        obj.element("autostart", autostart);
+        
+        resp.setContentType("application/json");
+        resp.getWriter().print(obj.toString());
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+
+        JSONObject obj = new JSONObject();
+
+		// gather settings to update
+		boolean updateAutostart = false, updatePort = false, updateRunning = false;
+		boolean autostart = false, running = false;
+		int port = 0;
+
+		String paramPort = req.getParameter("port");
+		if (paramPort != null) {
+			try {
+				port = Integer.parseInt(paramPort);
+				if (port <= 0 || port > 65535) {
+					throw new NumberFormatException();
+				}
+				updatePort = true;
+			} catch (NumberFormatException ex) {
+				obj.element("success", false);
+				obj.element("error", "Bad service port: must be a valid port number");
+				reply(resp, 400, obj);
+				return;
+			}
+		}
+
+        String paramAutostart = req.getParameter("autostart");
+        if (paramAutostart != null) {
+            autostart = Boolean.parseBoolean(paramAutostart);
+			updateAutostart = true;
+        }
+        
+        String paramRunning = req.getParameter("running");
+        if (paramRunning != null) {
+			running = Boolean.parseBoolean(paramRunning);
+			updateRunning = true;
+        }
+
+		final ControlServices controlServices = ControlServices.getInstance();
+		final ServerSettings serverSettings = ServerSettings.getInstance();
+
+		// update auto-start
+		if (updateAutostart) {
+			switch (mType) {
+				case STORAGE:
+					serverSettings.setStorage(autostart);
+					obj.element("autostart", autostart);
+					break;
+				case QUERY:
+					serverSettings.setQueryRetrive(autostart);
+					obj.element("autostart", autostart);
+					break;
+			}
+		}
+
+		// update port
+		if (updatePort) {
+			switch (mType) {
+				case STORAGE:
+					serverSettings.setStoragePort(port);
+					obj.element("port", port);
+					break;
+				case QUERY:
+					serverSettings.setWlsPort(port);
+					obj.element("port", port);
+					break;
+			}
+		}
+
+		// update running
+		if (updateRunning) {
+			switch (mType) {
+				case STORAGE:
+					if (running) {
+						controlServices.startStorage();
+						obj.element("running", true);
+					} else {
+						controlServices.stopStorage();
+						obj.element("running", false);
+					}
+					break;
+
+				case QUERY:
+					if (running) {
+						controlServices.startQueryRetrieve();
+						obj.element("running", true);
+
+					} else {
+						controlServices.stopQueryRetrieve();
+						obj.element("running", false);
+					}
+					break;
+
+				default:
+					break;
+			}
+		}
+		Services.getInstance().saveSettings();
+		obj.element("success", true);
+		reply(resp, 200, obj);
+	}
+
+	private static void reply(HttpServletResponse resp, int code, JSONObject object) throws IOException {
+		resp.setContentType("application/json");
+		resp.setStatus(code);
+		resp.getWriter().print(object.toString());
+	}
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/TransferOptionsServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/TransferOptionsServlet.java
new file mode 100644
index 0000000..d592673
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/TransferOptionsServlet.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONSerializer;
+import pt.ua.dicoogle.core.XMLSupport;
+import pt.ua.dicoogle.server.SOPList;
+import pt.ua.dicoogle.server.TransfersStorage;
+import pt.ua.dicoogle.server.web.utils.ResponseUtil;
+
+
+/**
+*
+* @author Frederico Silva<fredericosilva at ua.pt>
+*/
+public class TransferOptionsServlet extends HttpServlet {
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		String uid = req.getParameter("uid");
+		
+        resp.setContentType("application/json");
+		String soplist = SOPList.getInstance().getSOPList();
+		resp.getWriter().write(soplist);
+	}
+
+	@Override
+	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		
+		String UID = req.getParameter("uid");
+		String option = req.getParameter("option");
+		String valueS = req.getParameter("value");
+		boolean value = Boolean.parseBoolean(req.getParameter("value"));
+
+		SOPList.getInstance().updateTSField(UID, option, value);
+		new XMLSupport().printXML();
+		ResponseUtil.simpleResponse(resp, "success", true);
+	}
+
+    public static class TransferenceOptionsResponse {
+        List<Option> options;
+
+        public TransferenceOptionsResponse() {
+            options = new ArrayList<>();
+
+        }
+
+        public List<Option> getOptions() {
+            return options;
+        }
+
+        public void setOptions(List<Option> options) {
+            this.options = options;
+        }
+
+        public static TransferenceOptionsResponse fromBooleanList(boolean[] tsList) {
+            TransferenceOptionsResponse tor = new TransferenceOptionsResponse();
+            for (int i = 0; i < tsList.length; i++) {
+                tor.options.add(new Option(
+                        TransfersStorage.globalTransferMap.get(i), tsList[i]));
+            }
+            return tor;
+        }
+        
+        public static String getJSON(boolean[] tsList) {
+            TransferenceOptionsResponse tor = fromBooleanList(tsList);
+            return JSONSerializer.toJSON(tor).toString();
+        }
+
+        public static class Option {
+            String name;
+            boolean value;
+
+            public Option(String name, boolean value) {
+                this.name = name;
+                this.value = value;
+            }
+
+            public String getName() {
+                return name;
+            }
+
+            public void setName(String name) {
+                this.name = name;
+            }
+
+            public boolean isValue() {
+                return value;
+            }
+
+            public void setValue(boolean value) {
+                this.value = value;
+            }
+        }
+    }
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/UnindexServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/UnindexServlet.java
new file mode 100644
index 0000000..c5e851e
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/management/UnindexServlet.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.management;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pt.ua.dicoogle.plugins.PluginController;
+
+/** Unindexer servlet.
+ * 
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class UnindexServlet extends HttpServlet {
+
+    private static final Logger logger = LoggerFactory.getLogger(UnindexServlet.class);
+    
+    /**
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        // Getting Parameters.
+        String[] uris = req.getParameterValues("uri");
+        String[] providerArr = req.getParameterValues("provider");
+
+        List<String> providers = providerArr != null ? Arrays.asList(providerArr) : null;
+
+        if (uris == null) {
+            resp.sendError(400, "No uri provided");
+            return;
+        }
+
+        URI[] effUris = new URI[uris.length];
+        try {
+            for (int i = 0 ; i < effUris.length ; i++) {
+                effUris[i] = new URI(uris[i]);
+            }
+        } catch (URISyntaxException ex) {
+            logger.info("Received bad URI", ex);
+            resp.sendError(400, "Bad URI: " + ex.getInput());
+            return;
+        }
+
+        // unindex
+        for (URI uri : effUris) {
+            try {
+                PluginController.getInstance().unindex(uri, providers);
+            } catch (RuntimeException ex) {
+                logger.error(ex.getMessage(), ex);
+            }
+        }
+
+        logger.info("Finished unindexing {}", Arrays.asList(uris));
+        resp.setStatus(200);
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/DumpServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/DumpServlet.java
new file mode 100644
index 0000000..9c3ffd8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/DumpServlet.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.search;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import org.slf4j.LoggerFactory;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSONObject;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+
+import pt.ua.dicoogle.core.TagsXML;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+import pt.ua.dicoogle.sdk.utils.TagValue;
+import pt.ua.dicoogle.sdk.utils.TagsStruct;
+
+/**
+ * Dump of DICOM metadata
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class DumpServlet extends HttpServlet {
+    private static final Logger logger = LoggerFactory.getLogger(DumpServlet.class);
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String uid = req.getParameter("uid");
+        if (StringUtils.isEmpty(uid)) {
+            resp.sendError(400, "No uid supplied");
+        }
+        
+        String[] providerArr = req.getParameterValues("provider");
+        List<String> providers = (providerArr == null)
+                ? PluginController.getInstance().getQueryProvidersName(true)
+                : Arrays.asList(providerArr);
+        
+        String query = "SOPInstanceUID:" + uid;
+        
+        Set<TagValue> tags = TagsStruct.getInstance().getAllFields(); 
+        //TODO: PERHAPS REMOVE DICTIONARY ACCESS SINGLETON
+        
+        HashMap<String, String> extraFields = new HashMap<>();
+        for (TagValue s : tags) {
+        	if(!s.getVR().equalsIgnoreCase("SQ"))
+        		extraFields.put(s.getAlias(), s.getAlias());
+        }
+        
+        JointQueryTask queryTaskHolder = new JointQueryTask() {
+            @Override
+            public void onCompletion() {
+            }
+            @Override
+            public void onReceive(Task<Iterable<SearchResult>> e) {
+            }
+        };
+
+        long tick = System.currentTimeMillis();
+        Iterable<SearchResult> results;
+        try {
+            results = PluginController.getInstance().query(queryTaskHolder, providers, query, extraFields).get();
+        } catch (InterruptedException | ExecutionException ex) {
+            logger.warn("Failed to generate results", ex);
+            resp.sendError(500, "Could not generate results!");
+            return;
+        }
+
+        long time = System.currentTimeMillis()-tick;
+        String json = processJSON(results, time);
+
+        resp.setContentType("application/json");
+        resp.getWriter().append(json);
+    }
+
+    private static String processJSON(Iterable<SearchResult> results, long elapsedTime) {
+        JSONObject resp = new JSONObject();
+        JSONObject rj = new JSONObject();
+        JSONObject fields = new JSONObject();
+        for (SearchResult r : results) {
+            rj.put("uri", r.getURI().toString());
+            for (Map.Entry<String,Object> e : r.getExtraData().entrySet()) {
+                fields.put(e.getKey(), e.getValue());
+            }
+        }
+        rj.put("fields", fields);
+        resp.put("results", rj);
+        resp.put("elapsedTime", elapsedTime);
+        return resp.toString();
+    }
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ExportServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ExportServlet.java
new file mode 100644
index 0000000..26e1839
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ExportServlet.java
@@ -0,0 +1,126 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.search;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONArray;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.core.query.ExportToCSVQueryTask;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.utils.DictionaryAccess;
+
+public class ExportServlet extends HttpServlet{
+	private static final Logger logger = LoggerFactory.getLogger(ExportServlet.class);
+
+	public enum ExportType{
+		LIST, EXPORT_CVS;
+	}
+	private ExportType type;
+	
+	public ExportServlet(ExportType type) {
+		this.type = type;
+	}
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		switch(type){
+		case LIST:
+			doGetTagList(req, resp);
+			break;
+		case EXPORT_CVS:
+			doGetExportCvs(req, resp);
+			break;
+		}
+	}
+	
+	private void doGetTagList(HttpServletRequest req, HttpServletResponse resp) throws IOException{
+		HashMap< String, Integer> tagList = DictionaryAccess.getInstance().getTagList();
+		Iterator iterator = tagList.entrySet().iterator();
+		
+		JSONArray array = new JSONArray();
+		
+		while(iterator.hasNext())
+		{
+			Map.Entry<String, Integer> entry = (Entry<String, Integer>) iterator.next();
+			//JSONObject obj = new JSONObject();
+			//obj.put("key", entry.getKey());
+			//obj.put("value", entry.getValue());
+			
+			
+			array.add(entry.getKey());
+		}
+		
+		resp.getWriter().write(array.toString());
+	}
+	
+	private void doGetExportCvs(HttpServletRequest req, HttpServletResponse resp) throws IOException{
+		resp.setHeader("Content-disposition","attachment; filename=QueryResultsExport.csv");
+		String queryString = req.getParameter("query");
+		String[] fields = req.getParameterValues("fields");
+		String[] providers = req.getParameterValues("providers");
+		boolean keyword = Boolean.parseBoolean(req.getParameter("keyword"));
+		
+		logger.debug("queryString: {}", queryString);
+		logger.debug("fields: {}", Arrays.asList(fields));
+		logger.debug("keyword: {}", keyword);
+		
+		if(queryString == null)
+			resp.sendError(401, "Query Parameters not found");
+		
+		if(fields == null || fields.length==0)
+			resp.sendError(402, "Fields Parameters not found");
+		
+		if (!keyword) {
+            QueryExpressionBuilder q = new QueryExpressionBuilder(queryString);
+            queryString = q.getQueryString();
+        }
+
+						    	
+	    List<String> fieldList = Arrays.asList(fields);
+	    Map<String, String> fieldsMap = new HashMap<>();
+	    for(String f : fields){
+	    	fieldsMap.put(f, f);
+	    }
+	    	    	    
+    	ExportToCSVQueryTask task = new ExportToCSVQueryTask( fieldList,
+				resp.getOutputStream());
+
+    	if(providers == null || providers.length == 0) {
+			PluginController.getInstance().queryAll(task, queryString, fieldsMap);
+		} else {
+			List<String> providersList = Arrays.asList(providers);
+			PluginController.getInstance().query(task, providersList, queryString,
+					fieldsMap);
+		}
+
+		task.await();
+	}
+
+	
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ProvidersServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ProvidersServlet.java
new file mode 100644
index 0000000..2d58ff8
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/ProvidersServlet.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.search;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONArray;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.DicooglePlugin;
+
+/**
+ * Retrieve active providers
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class ProvidersServlet extends HttpServlet{
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+        String paramType = req.getParameter("type");
+        
+        final String type = paramType != null ? paramType : "query";
+		Collection<String> activeProviders;
+        switch (type) {
+            case "index":
+                activeProviders = getIndexerNames();
+                break;
+            case "storage":
+                activeProviders = getStorageNames();
+                break;
+            case "query":
+                activeProviders = PluginController.getInstance().getQueryProvidersName(true);
+                break;
+            default:
+                resp.sendError(400);
+                return;
+        }
+		
+        JSONArray json = new JSONArray();
+        json.addAll(activeProviders);
+		
+        resp.setContentType("application/json");
+		resp.getWriter().print(json.toString());
+			
+	}
+	
+    private static Collection<String> getIndexerNames() {
+        return getPluginNames(PluginController.getInstance().getIndexingPlugins(true));
+    }
+
+    private Collection<String> getStorageNames() {
+        return getPluginNames(PluginController.getInstance().getStoragePlugins(true));
+    }
+    
+    private static Collection<String> getPluginNames(Collection<? extends DicooglePlugin> plugins) {
+        Collection<String> c = new ArrayList<>(plugins.size());
+        for (DicooglePlugin p : plugins) {
+            c.add(p.getName());
+        }
+        return c;
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/SearchServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/SearchServlet.java
new file mode 100644
index 0000000..0eeb131
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/SearchServlet.java
@@ -0,0 +1,280 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.search;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.util.*;
+
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+
+import net.sf.json.JSONArray;
+import org.apache.commons.collections.ArrayStack;
+import org.json.JSONException;
+import org.json.JSONWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.core.QueryExpressionBuilder;
+import pt.ua.dicoogle.core.dim.DIMGeneric;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * Search the DICOM metadata, perform queries on images. Returns the data in JSON.
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class SearchServlet extends HttpServlet {
+    private static final Logger logger = LoggerFactory.getLogger(SearchServlet.class);
+
+    private static final long serialVersionUID = 1L;
+  
+    private final Collection<String> DEFAULT_FIELDS = Arrays.asList(
+            "SOPInstanceUID", "StudyInstanceUID", "SeriesInstanceUID", "PatientID",
+            "PatientName",    "PatientSex",       "Modality",          "StudyDate",
+            "StudyID",        "StudyDescription", "SeriesNumber",      "SeriesDescription",
+            "InstitutionName", "uri");
+  
+  	public enum SearchType {
+      ALL, PATIENT;
+  	}
+  	private final SearchType searchType;
+  	public SearchServlet(){
+  		searchType = SearchType.ALL;
+  	}
+  	public SearchServlet(SearchType stype){
+  		if(stype == null)
+  			searchType = SearchType.ALL;
+  		else
+  		searchType = stype;
+  	}
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+        /*
+         Example: http://localhost:8080/search?query=wrix&keyword=false&provider=lucene&psize=10&offset=10
+         */
+        response.setContentType("application/json");
+
+        String query = request.getParameter("query");
+        String providers[] = request.getParameterValues("provider");
+        boolean keyword = Boolean.parseBoolean(request.getParameter("keyword"));
+        String[] fields = request.getParameterValues("field");
+
+        final int psize;
+        final int offset;
+        final int depth;
+        try {
+            psize = getReqParameter(request, "psize", Integer.MAX_VALUE);
+            if (psize < 0) throw new NumberFormatException();
+        } catch (NumberFormatException e) {
+            sendError(response, 400, "Invalid parameter psize: must be a non-negative integer");
+            return;
+        }
+        try {
+            offset = getReqParameter(request, "offset", 0);
+            if (offset < 0) throw new NumberFormatException();
+        } catch (NumberFormatException e) {
+            sendError(response, 400, "Invalid parameter offset: must be a non-negative integer");
+            return;
+        }
+        String paramDepth = request.getParameter("depth");
+        if (paramDepth != null) {
+            if (this.searchType != SearchType.PATIENT) {
+                sendError(response, 400, "Parameter depth is only applicable to /searchDIM endpoint");
+                return;
+            }
+            switch (paramDepth.toLowerCase()) {
+                case "none": depth = 0; break;
+                case "patient": depth = 1; break;
+                case "study": depth = 2; break;
+                case "series": depth = 3; break;
+                case "image": depth = 4; break;
+                default:
+                sendError(response, 400, "Invalid parameter depth: must be a valid level: "
+                        + "'none', 'patient', 'study', 'series' or 'image'");
+                return;
+            }
+        } else {
+            depth = 4;
+        }
+
+        // retrieve desired fields
+        Set<String> actualFields;
+        if (fields == null || fields.length == 0) {
+            actualFields = null;
+        } else {
+            actualFields = new HashSet<>(Arrays.asList(fields));
+        }
+
+        if (StringUtils.isEmpty(query)) {
+            sendError(response, 400, "No query supplied!");
+            return;
+        }
+        
+        if (!keyword) {
+            QueryExpressionBuilder q = new QueryExpressionBuilder(query);
+            query = q.getQueryString();
+        }
+
+        List<String> providerList;
+        boolean queryAllProviders = false;
+        if (providers == null || providers.length == 0) {
+            queryAllProviders = true;
+        } else {
+            providerList = Arrays.asList(providers);
+            if (providerList.isEmpty()) {
+                queryAllProviders = true;
+            }
+        }
+
+        List<String> knownProviders = null;
+        if (!queryAllProviders) 
+        {
+            knownProviders = new ArrayList<>();
+            List<String> activeProviders = PluginController.getInstance().getQueryProvidersName(true);
+            for (String p : providers)
+            {
+                if (activeProviders.contains(p)) 
+                {
+                    knownProviders.add(p);
+                }
+                else
+                {
+                    response.setStatus(400);
+                    JSONObject obj = new JSONObject();
+                    obj.put("error", p.toString() +" is not a valid query provider");
+                    response.getWriter().append(obj.toString());
+                    return;
+                }
+            }
+        }
+        
+        HashMap<String, String> extraFields = new HashMap<>();
+        if (actualFields == null) {
+            
+            //attaches the required extrafields
+            for (String field : DEFAULT_FIELDS) {
+                extraFields.put(field, field);
+            }
+        } else {
+            for (String f : actualFields) {
+                extraFields.put(f, f);
+            }
+        }
+        
+        JointQueryTask queryTaskHolder = new JointQueryTask() {
+
+            @Override
+            public void onCompletion() {
+            }
+
+            @Override
+            public void onReceive(Task<Iterable<SearchResult>> e) {
+            }
+        };
+
+        try {
+            long elapsedTime = System.currentTimeMillis();
+            Iterable<SearchResult> results;
+            if (queryAllProviders) {
+                results = PluginController.getInstance().queryAll(queryTaskHolder, query, extraFields).get();
+            }
+            
+            else {
+                results = PluginController.getInstance().query(queryTaskHolder, knownProviders, query, extraFields).get();
+            }
+
+            if (this.searchType == SearchType.PATIENT) {
+                try {
+                    DIMGeneric dimModel = new DIMGeneric(results, depth);
+                    elapsedTime = System.currentTimeMillis() - elapsedTime;
+                    dimModel.writeJSON(response.getWriter(), elapsedTime, depth, offset, psize);
+                } catch (Exception e) {
+                    logger.warn("Failed to get DIM", e);
+                }
+            } else {
+                elapsedTime = System.currentTimeMillis() - elapsedTime;
+                this.writeResponse(response, results, elapsedTime, offset, psize);
+            }
+
+        } catch (InterruptedException | ExecutionException | RuntimeException ex) {
+            logger.error("Failed to retrieve results", ex);
+            sendError(response, 500, "Could not generate results");
+            return;
+        } catch (JSONException e) {
+            logger.error("Failed to serialize results", e);
+            return;
+        }
+    }
+
+    private void writeResponse(HttpServletResponse resp, Iterable<SearchResult> results, long elapsedTime, int offset, int psize) throws IOException, JSONException {
+        JSONWriter writer = new JSONWriter(resp.getWriter());
+        writer.object(); //begin output
+        // results
+        writer.key("results").array(); // begin results
+        int count = 0;
+        for (Iterator<SearchResult> it = results.iterator(); it.hasNext(); ++count) {
+            SearchResult res = it.next();
+            if (count < offset || count >= offset + psize) continue;
+            writer.object() // begin result
+                    .key("uri").value(res.getURI().toString())
+                    .key("fields").object();
+            for (Map.Entry<String, Object> e : res.getExtraData().entrySet()) {
+                writer.key(e.getKey()).value(String.valueOf(e.getValue()).trim());
+            }
+            writer.endObject().endObject(); // end result
+        }
+        // other fields
+        writer.endArray() // end results
+                .key("elapsedTime").value(elapsedTime)
+                .key("numResults").value(count);
+        writer.endObject(); // end output
+    }
+
+    private int getReqParameter(HttpServletRequest req, String name, int defaultValue) throws NumberFormatException {
+        String param = req.getParameter(name);
+        int val = defaultValue;
+        if (param != null) {
+            val = Integer.parseInt(param);
+        }
+        return val;
+    }
+
+    private static void sendError(HttpServletResponse resp, int code, String message) throws IOException {
+        resp.setStatus(code);
+        JSONObject obj = new JSONObject();
+        obj.put("results", new JSONArray());
+        obj.put("error", message);
+        resp.getWriter().append(obj.toString());
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/WadoServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/WadoServlet.java
new file mode 100644
index 0000000..a6c8f06
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/search/WadoServlet.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.servlets.search;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.ExecutionException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ * @todo
+ */
+public class WadoServlet extends HttpServlet{
+
+	@Override
+	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+			throws ServletException, IOException {
+		
+		String uid = req.getParameter("uid");
+		if (StringUtils.isEmpty(uid)) {
+            resp.sendError(400, "No uid supplied!\n"
+            		+ "/wado?uid=UID");
+            return;
+        }
+		
+		String query = "SOPInstanceUID:" + uid;
+		
+		HashMap<String, String> extraFields = new HashMap<>();
+        extraFields.put("SOPInstanceUID", "SOPInstanceUID");
+		
+		PluginController pc = PluginController.getInstance();
+        JointQueryTask task = new MyHolder();
+        
+        Iterable<SearchResult> results = null;
+        try {
+			results = pc.queryAll(task, query, extraFields).get();
+		} catch (InterruptedException | ExecutionException e) {
+			e.printStackTrace();
+		}
+        
+        
+        String uri ="not";
+        
+        ArrayList<SearchResult> resultsArr = new ArrayList<>();
+        for (SearchResult r : results) {
+            resultsArr.add(r);
+            
+            uri = r.getURI().toURL().toString();
+        }
+        
+        resp.getWriter().print(uri);
+	}
+	
+	 private static class MyHolder extends JointQueryTask {
+         
+	        @Override
+	        public void onCompletion() {
+	        }
+
+	        @Override
+	        public void onReceive(Task<Iterable<SearchResult>> e) {
+	        }
+	    }    
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIModuleServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIModuleServlet.java
new file mode 100644
index 0000000..32d2798
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIModuleServlet.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.webui;
+
+import org.apache.commons.codec.binary.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.plugins.webui.WebUIPlugin;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+
+/**
+ * Retrieval of web UI plugins and respective packages/modules.
+ * 
+ * <b>This API is unstable. It is currently only compatible with dicoogle-webcore 0.14.x</b>
+ *
+ * @author Eduardo Pinho
+ */
+public class WebUIModuleServlet extends HttpServlet {
+    private static final Logger logger = LoggerFactory.getLogger(WebUIModuleServlet.class);
+    
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String name = req.getRequestURI().substring("/webui/module/".length());
+        if (name.isEmpty()) {
+            resp.sendError(400);
+            return;
+        }
+        logger.debug("Service request: retrieve webplugin module {}", name);
+
+        String process = req.getParameter("process");
+
+        resp.setContentType("application/javascript");
+        boolean doProcess = process == null || Boolean.parseBoolean(process);
+
+        WebUIPlugin plugin = PluginController.getInstance().getWebUIPlugin(name);
+        if (plugin == null) {
+            resp.sendError(404);
+            return;
+        }
+        String js = PluginController.getInstance().getWebUIModuleJS(name);
+
+        this.writeModule(resp.getWriter(), name, js, doProcess);
+    }
+
+    /** Convert from dash-lowercase to camelCase
+     * @param s a string in dash-lowercase
+     * @return a string in camelCase
+     */
+    public static String camelize(String s) {
+        String [] words = s.split("-");
+        if (words.length == 0) return "";
+        String t = words[0];
+        for (int i = 1 ; i < words.length ; i++) {
+            if (!words[i].isEmpty()) {
+                t += Character.toUpperCase(words[i].charAt(0)) + words[i].substring(1);
+            }
+        }
+        return t;
+    }
+
+    public static boolean isPrerelease(String version) {
+        return version.indexOf('-') != -1;
+    }
+    
+    public static void writeModule(Writer writer, String name, String module, boolean process) throws IOException {
+        if (process) {
+            writer.append("(function(r,f){\n");
+            writer.append("var w=r.DicoogleWebcore||require(\"dicoogle-webcore\");");
+            writer.append("if (w.__esModule)w=w.default;");
+            writer.append("var c=(r.Dicoogle||require(\"dicoogle-client\"))();");
+            writer.append("var m={exports:{}};");
+            writer.append("f(c,m,m.exports);");
+            writer.append("var o=m.exports.__esModule?m.exports.default:m.exports;");
+            writer.append("w.constructors[\"");
+              writer.append(name);
+              writer.append("\"]=o;");
+            writer.append("w.onRegister(new o(),\"");
+              writer.append(name);
+              writer.append("\");");
+            writer.append("})(this,function(Dicoogle,module,exports){\n");
+        }
+        writer.append(module);
+        if (process) {
+            writer.append("});\n");
+        }
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIServlet.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIServlet.java
new file mode 100644
index 0000000..c174354
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/servlets/webui/WebUIServlet.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.servlets.webui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.plugins.webui.WebUIPlugin;
+import pt.ua.dicoogle.server.users.Role;
+import pt.ua.dicoogle.server.users.RolesStruct;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.web.auth.Authentication;
+
+/**
+ * Retrieval of web UI plugins and respective packages/modules.
+ * 
+ * <b>This API is unstable. It is currently only compatible with dicoogle-webcore >= 0.12.x && <= 0.14.x</b>
+ *
+ * @author Eduardo Pinho
+ */
+public class WebUIServlet extends HttpServlet {
+    private static final Logger logger = LoggerFactory.getLogger(WebUIServlet.class);
+    
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String name = req.getParameter("name");
+        String[] slotIdArr = req.getParameterValues("slot-id");
+        String module = req.getParameter("module");
+        String process = req.getParameter("process");
+
+        resp.setContentType("application/json");
+        if (name != null) {
+            resp.getWriter().append(this.getPlugin(resp, name));
+        } else if (module != null) {
+            /**
+             * deprecated: Use {@link WebUIModuleServlet} instead
+             */
+            resp.setContentType("application/javascript");
+            boolean doProcess = process == null || Boolean.parseBoolean(process);
+            resp.sendRedirect("/webui/module/" + module + (!doProcess ? "?process=false" : ""));
+        } else {
+            resp.getWriter().append(this.getPluginsBySlot(req, slotIdArr));
+        }
+    }
+
+    /** Retrieve plugins. */
+    private String getPluginsBySlot(HttpServletRequest req, String... slotIds) throws IOException {
+        String token = req.getHeader("Authorization");
+        User user = Authentication.getInstance().getUsername(token);
+
+        Collection<WebUIPlugin> plugins = PluginController.getInstance().getWebUIPlugins(slotIds);
+        List<String> pkgList = new ArrayList<>(plugins.size());
+        for (WebUIPlugin plugin : plugins) {
+
+            String pkg = PluginController.getInstance().getWebUIPackageJSON(plugin.getName());
+            boolean hasUserAllowPlugin= false;
+            for (String r:plugin.getRoles())
+            {
+                Role rr = RolesStruct.getInstance().getRole(r);
+
+                hasUserAllowPlugin = RolesStruct.getInstance().hasRole(user, rr);
+                if (hasUserAllowPlugin)
+                    break;
+            }
+
+
+            if (pkg != null&&(hasUserAllowPlugin||(user!=null&&user.isAdmin()))) {
+                pkgList.add(pkg);
+            }
+        }
+        JSONObject o = new JSONObject();
+        JSONArray pkgArr = new JSONArray();
+        for (String n : pkgList) {
+            pkgArr.add(n);
+        }
+        o.element("plugins", pkgArr);
+        return o.toString();
+    }
+
+    private String getPlugin(HttpServletResponse resp, String name) throws IOException {
+        resp.setContentType("application/json");
+        String json = PluginController.getInstance().getWebUIPackageJSON(name);
+        return json;
+    }
+
+    /** Convert from dash-lowercase to camelCase
+     * @param s a string in dash-lowercase
+     * @return a string in camelCase
+     */
+    public static String camelize(String s) {
+        String [] words = s.split("-");
+        if (words.length == 0) return "";
+        StringBuilder t = new StringBuilder();
+        t.append(words[0]);
+        for (int i = 1 ; i < words.length ; i++) {
+            if (!words[i].isEmpty()) {
+                t.append(Character.toUpperCase(words[i].charAt(0)));
+                t.append(words[i].substring(1));
+            }
+        }
+        return t.toString();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/DIM2JSONConverter.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/DIM2JSONConverter.java
new file mode 100644
index 0000000..63f9721
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/DIM2JSONConverter.java
@@ -0,0 +1,146 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+import java.net.URI;
+import java.util.Iterator;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.apache.commons.lang3.StringUtils;
+
+import pt.ua.dicoogle.core.dim.DIMGeneric;
+import pt.ua.dicoogle.core.dim.Patient;
+import pt.ua.dicoogle.core.dim.Serie;
+import pt.ua.dicoogle.core.dim.Study;
+
+/**
+ * Helper Class to tranlate DIMGeneric objects into JSON.
+ * Usefull for web environments
+ * 
+ * TODO: Insert proper documentation.
+ * 
+ * @author Tiago Marques Godinho.
+ *
+ */
+public class DIM2JSONConverter {
+	
+	/**
+	 * Converts a DIMGeneric object to JSON.
+	 * 
+	 * @param dim DIM Object
+	 * @return The resulting JSON Objects, or null if dim is null.
+	 */
+	public static JSONArray convertToJSON(DIMGeneric dim){
+		JSONArray arr = new JSONArray();
+		
+		Iterator<Patient> it = dim.getPatients().iterator();
+		while(it.hasNext()){
+			Patient p = it.next();
+				
+			arr.add(convertToJSON(p));
+		}
+		
+		return arr;
+	}
+	
+	/**
+	 * Converts a Patient Object to JSON.
+	 * 
+	 * @param patient Patient to be Converted
+	 * @return The resulting JSON Object, or null if patient is null.
+	 */
+	public static JSONObject convertToJSON(Patient patient){
+		
+		JSONObject obj = new JSONObject();
+		
+		obj.put("id", StringUtils.trimToNull(patient.getPatientID()));
+		obj.put("name", StringUtils.trimToNull(patient.getPatientName()));
+		obj.put("sex", StringUtils.trimToNull(patient.getPatientSex()));
+		
+		JSONArray studies = new JSONArray();
+		for(Study s : patient.getStudies()){
+			studies.add(convertToJSON(s));
+		}
+		obj.put("studies", studies);
+		
+		return obj;		
+	}
+
+		
+	/**
+	 * Converts a Study Object to JSON.
+	 * 
+	 * @param study Study to be converted.
+	 * @return The resulting JSON Object, or null if study is null. 
+	 */
+	private static JSONObject convertToJSON(Study study) {
+		
+		JSONObject obj = new JSONObject();
+		
+		obj.put("id",StringUtils.trimToNull( study.getStudyID()));
+		obj.put("uid", StringUtils.trimToNull(study.getStudyInstanceUID()));
+		obj.put("data", StringUtils.trimToNull(study.getStudyData()));
+		obj.put("time", StringUtils.trimToNull(study.getStudyTime()));
+		obj.put("descr", StringUtils.trimToNull(study.getStudyDescription()));
+		obj.put("iname", StringUtils.trimToNull(study.getInstitutuionName()));
+		
+		JSONArray series = new JSONArray();
+		for(Serie serie : study.getSeries()){
+			series.add(convertToJSON(serie));
+		}
+		obj.put("series", series);
+		
+		return obj;
+	}
+	
+	/**
+	 * Converts a Series Model to JSON. 
+	 * 
+	 * @param serie The DICOM Series model
+	 * @return The resulting JSON object, or null if serie is null.
+	 */
+	private static JSONObject convertToJSON(Serie serie) {
+		
+		JSONObject obj = new JSONObject();
+		
+		obj.put("uid", StringUtils.trimToNull(serie.getSerieInstanceUID()));
+		obj.put("mod", StringUtils.trimToNull(serie.getModality()));
+		obj.put("number", serie.getSerieNumber());
+		obj.put("descr", StringUtils.trimToNull(serie.getSeriesDescription()));
+	
+		JSONArray images = new JSONArray();
+		Iterator<String> itUID = serie.getSOPInstanceUIDList().iterator();
+		Iterator<URI> itURI = serie.getImageList().iterator();
+		while(itUID.hasNext() && itURI.hasNext()){
+			String uid = itUID.next();
+			URI uri = itURI.next();
+			
+			JSONObject imgObj = new JSONObject();
+			imgObj.put("uid", uid);
+			imgObj.put("uri", uri.toString());
+			
+			images.add(imgObj);
+		}
+		obj.put("images", images);
+		
+		return obj;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageLoader.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageLoader.java
new file mode 100644
index 0000000..2b88567
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageLoader.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+
+/**
+ * A utility library for loading images.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class ImageLoader {
+    
+    private ImageLoader() {
+    }
+    
+    static {
+        ImageIO.scanForPlugins();
+    }
+    
+    /**
+     * Obtain an image from an ordinary input stream. This method will attempt to automatically use the
+     * appropriate image reader for the image's format, including DICOM.
+     *
+     * @param inputStream the input stream to retrieve the image from
+     * @return a buffered image
+     * @throws IOException if the image format is not supported or another IO issue occurred
+     */
+    public static BufferedImage loadImage(InputStream inputStream) throws IOException {
+        BufferedImage image;
+        try (ImageInputStream imageInputStream
+                = ImageIO.createImageInputStream(inputStream)) {
+
+            Iterator<ImageReader> readers = ImageIO.getImageReaders(imageInputStream);
+            if (!readers.hasNext()) {
+                throw new IOException("Unsupported image format");
+            }
+            ImageReader reader = readers.next();
+            reader.setInput(imageInputStream, false);
+            if (reader.getFormatName().equalsIgnoreCase("DICOM")) {
+                DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();
+                image = reader.read(0, param);
+            } else {
+                image = reader.read(0);
+            }
+        } catch (org.dcm4che2.data.ConfigurationError | IOException ex) {
+            LoggerFactory.getLogger(ImageLoader.class).debug("Failed to load image reader, attempting special DICOM reading mechanism", ex);
+            image = loadDICOMImage(inputStream);
+        }
+        return image;
+    }
+    
+    /**
+     * Obtain an image from a Dicoogle storage input stream. This method will attempt to automatically use the
+     * appropriate image reader for the image's format, including DICOM.
+     *
+     * @param imageFromStorage the storage input stream to retrieve the image from
+     * @return a buffered image
+     * @throws IOException if the image format is not supported or another IO issue occurred
+     */
+    public static BufferedImage loadImage(StorageInputStream imageFromStorage) throws IOException {
+        return loadImage(imageFromStorage.getInputStream());
+    }
+
+    /**
+     * Obtain a DICOM image from an orginary input stream. This method will attempt to read the file in
+     * storage as a DICOM file only.
+     *
+     * @param inputStream the input stream to retrieve the DICOM image from
+     * @return a buffered image
+     * @throws IOException if the image format is not DICOM or another IO issue occurred
+     */
+    public static BufferedImage loadDICOMImage(InputStream inputStream) throws IOException {
+        try (ImageInputStream imageInputStream
+                = ImageIO.createImageInputStream(inputStream)) {
+            Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
+            ImageReader reader = iter.next();
+            DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();
+            reader.setInput(imageInputStream, false);
+            BufferedImage img = reader.read(0, param);
+            return img;
+        }
+    }
+    
+    /**
+     * Obtain a DICOM from a Dicoogle storage input stream. This method will attempt to read the file in
+     * storage as a DICOM file only.
+     *
+     * @param imageFromStorage the storage input stream to retrieve the DICOM image from
+     * @return a buffered image
+     * @throws IOException if the image format is not DICOM or another IO issue occurred
+     */
+    public static BufferedImage loadDICOMImage(StorageInputStream imageFromStorage) throws IOException {
+        return loadDICOMImage(imageFromStorage.getInputStream());
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageRetriever.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageRetriever.java
new file mode 100644
index 0000000..6a8004d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ImageRetriever.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+/** Interface for retrieving the image content of an instance, in a format compatible with browsers.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public interface ImageRetriever {
+
+    /** Obtain an image by URI.
+     * 
+     * @param uri the URI to the image
+     * @param frame the frame number
+     * @param thumbnail whether to retrieve a thumbnail (true) or the image in its original size (false)
+     * @return an input stream for retrieving the image's content
+     * @throws IOException 
+     */
+    public InputStream get(URI uri, int frame, boolean thumbnail) throws IOException;
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/LocalImageCache.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/LocalImageCache.java
new file mode 100644
index 0000000..f516ece
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/LocalImageCache.java
@@ -0,0 +1,301 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import pt.ua.dicoogle.server.web.dicom.Convert2PNG;
+
+/**
+ * Handles the caching of PNG images generated by the Image Servlet.
+ * The cached images are kept inside a temporary directory created inside the user (or system) temporary directory.
+ * These are maintained for a maximum period of time if they are not used, and deleted on a regular basis to save disk space while not hurting the cache performance.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class LocalImageCache extends Thread implements ImageRetriever
+{
+	/**
+	 * The number of milliseconds to wait between pool cache directory pooling.
+	 */
+	private volatile int interval;
+	/**
+	 * The number of milliseconds that a file can stay in the cache without being used/read.
+	 */
+	private volatile int maxAge;
+
+	private final File cacheFolder;
+	private volatile boolean running;
+
+	private final ConcurrentMap<String,File> filesBeingWritten;
+    
+    private final ImageRetriever under;
+
+	/**
+	 * Creates a local image cache that pools its cache directory at interval rates and deletes files older than maxAge.
+	 *
+	 * @param name the name of the cache directory.
+	 * @param interval the number of seconds to wait between pool cache directory pooling.
+	 * @param maxAge the number of seconds that a file can stay in the cache without being used/read.
+     * @param under the underlying image retriever
+	 */
+	public LocalImageCache(String name, int interval, int maxAge, ImageRetriever under)
+	{
+        super("cache-" + name);
+        Objects.requireNonNull(under);
+
+		if (interval < 1) {
+			this.interval = 1;
+		} else {
+			this.interval = interval;
+		}
+		this.interval *= 1000;
+
+		if (maxAge < 1) {
+            throw new IllegalArgumentException("Illegal maxAge");
+        }
+        this.maxAge = maxAge * 1000;
+
+		filesBeingWritten = new ConcurrentSkipListMap<>();
+		running = false;
+        
+        this.setDaemon(true);
+        this.under = under;
+        
+		// create the temporary directory
+		File sysTmpDir = new File(System.getProperty("java.io.tmpdir"));
+		cacheFolder = new File(sysTmpDir, name);
+	}
+
+	/**
+	 * Deletes a directory and all its contents.
+	 *
+	 * @param dir the directory to delete.
+	 */
+	private static void deleteDirectory(File dir)
+	{
+		if ((dir == null) || (! dir.exists())) {
+			return;
+		}
+
+		// delete all the files and folders inside this folder
+		for (File f : dir.listFiles()) {
+			if (f.isDirectory()) {
+				// if it's a sub-directory then delete its content
+				deleteDirectory(f);
+			} else {
+				f.delete();
+			}
+		}
+
+		// remove the folder
+		dir.delete();
+	}
+
+	@Override
+	public void start()
+	{
+		// abort if we couldn't make the temp dir
+		if (cacheFolder == null)
+			return;
+		if (! cacheFolder.exists())
+			if (! cacheFolder.mkdirs())
+				return;
+		cacheFolder.deleteOnExit();
+
+		// start running
+		super.start();
+	}
+
+	@Override
+	public void run()
+	{
+		// if the cache isn't setup abort
+		if (! cacheFolder.exists())
+			return;
+
+		running = true;
+		do
+		{
+			// check if there are any files worh deleting and if so do it
+			checkAndRemoveOldFiles();
+
+			// wait for the defined interval to be over
+			try {
+				Thread.sleep(interval);
+			} catch (InterruptedException ex) {
+				// do nothing
+			}
+		}
+		while (isRunning());
+	}
+
+	/**
+	 * Stop this cache from checking for old files.
+	 */
+	public synchronized void terminate()
+	{
+		this.running = false;
+
+		// if needed wake the thread from its sleeping state
+		this.interrupt();
+
+		// clear and delete the temporary folder
+		deleteDirectory(cacheFolder);
+	}
+
+	/**
+	 * Loops through the cache folder and tries to removes old/un-used files.
+	 */
+	private synchronized void checkAndRemoveOldFiles()
+	{
+		// if the cache isn't setup abort
+		if (! cacheFolder.exists())
+			return;
+
+		long currentTime = System.currentTimeMillis();
+
+		// go through all the files inside the temp folder and check their last access
+		for (File f : cacheFolder.listFiles())
+		{
+			// skip if the current file is a folder
+			if (f.isDirectory())
+				continue;
+
+			// check the last access done to the file, and if it's "past its due" tries to delete it
+			if (currentTime - f.lastModified() > maxAge)
+				f.delete();
+		}
+	}
+
+	/**
+	 * @return the interval
+	 */
+	public int getInterval()
+	{
+		return interval;
+	}
+
+	/**
+	 * @param interval the interval to set
+	 */
+	public void setInterval(int interval)
+	{
+		if (interval < 1) {
+			this.interval = 1;
+		} else {
+			this.interval = interval;
+		}
+		this.interval *= 1000;
+	}
+
+	/**
+	 * @return the maxAge
+	 */
+	public int getMaxAge()
+	{
+		return maxAge;
+	}
+
+	/**
+	 * @param maxAge the maxAge to set
+	 */
+	public void setMaxAge(int maxAge)
+	{
+		if (maxAge > 1) {
+			this.maxAge = maxAge;
+		}
+	}
+    
+    protected static String toFileName(String imageUri, int frameNumber, boolean thumbnail) {
+        String filename = imageUri.replace('/', '_') + "_" + frameNumber;
+        filename = filename.replace(':', '_') ; // only for windows.
+        if (thumbnail) {
+            filename += "__thumb";
+        }
+        return filename + ".png";
+    }
+    
+    @Override
+    public InputStream get(URI uri, final int frameNumber, final boolean thumbnail) throws IOException {
+        File f = this.implGetFile(toFileName(uri.toString(), frameNumber, thumbnail));
+        synchronized(f) {
+            if (f.exists()) {
+                return new FileInputStream(f);
+            }
+        }
+        this.implCreateFile(f);
+        byte[] imageArray;
+        synchronized (f) {
+            InputStream istream = this.under.get(uri, frameNumber, thumbnail);
+            ByteArrayOutputStream result = Convert2PNG.DICOM2PNGStream(istream, frameNumber);
+            imageArray = result.toByteArray();
+
+            // create new cache file with the converted image
+            try (FileOutputStream fout = new FileOutputStream(f)) {
+                fout.write(imageArray);
+            }
+            filesBeingWritten.remove(f.getAbsolutePath());
+        }
+        
+        // and return it
+        return new ByteArrayInputStream(imageArray);
+    }
+
+	private File implGetFile(String fileName) throws IOException {
+		// check if the file is currently being written to
+        String thatFilePath = new File(fileName).getAbsolutePath();
+        File f = this.filesBeingWritten.get(thatFilePath);
+        if (f == null) {
+            f = new File(cacheFolder, fileName);
+        }
+        return f;
+	}
+    
+    private File implCreateFile(File f) throws IOException {
+        //f.createNewFile();
+        f.deleteOnExit();
+		// if it does not exist add it to the list of files being written (because new content is going to be written to it outside this class) and create the empty file
+		filesBeingWritten.put(f.getAbsolutePath(), f);
+		// return the common handle to the currently created and empty file
+        return f;
+    }
+
+	/**
+	 * @return if the caching mechanism for checking and removing old/un-used cache files is still running
+	 */
+	public boolean isRunning()
+	{
+		return running;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Pages.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Pages.java
new file mode 100644
index 0000000..395ccf6
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Pages.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Provides some utility functions that can be used when handling JSP generation.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Pages
+{
+	/**
+	 * Retrieves the currently request page file name.
+	 * Based on http://stackoverflow.com/a/11150213
+	 *
+	 * @param request the Http servlet request object.
+	 * @return the currently request page file name.
+	 */
+	public static String getCurrentPageFileName(HttpServletRequest request)
+	{
+		String uri = request.getRequestURI();
+		return uri.substring(uri.lastIndexOf("/") + 1);
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Query.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Query.java
new file mode 100644
index 0000000..f2795dd
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/Query.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+/**
+ * Provides some functions for handling query builds easier.
+ *
+ * @author Antonio
+ */
+public class Query
+{
+	/**
+	 * For an input query adds the extra param to it, correctly.
+	 *
+	 * @param query the "up-to-now" query that we want to add the extra param to.
+	 * @param param the param to add to the query.
+	 * @param operator the logical operator to add between params.
+	 * @return the new query that has the new/extra param on it.
+	 */
+	public static String addExtraQueryParam(String query, String param, String operator)
+	{
+		String result = query;
+
+		// check if this is not the only param in the query
+		if (! result.isEmpty())
+			result += " " + operator + " ";
+
+		// add the extra param
+		result += param;
+
+		return result;
+	}
+
+	/**
+	 * Same as the overloaded version, but the operator is AND.
+	 *
+	 * @param query the "up-to-now" query that we want to add the extra param to.
+	 * @param param the param to add to the query.
+	 * @return the new query that has the new/extra param on it.
+	 */
+	public static String addExtraQueryParam(String query, String param)
+	{
+		return addExtraQueryParam(query, param, "AND");
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ResponseUtil.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ResponseUtil.java
new file mode 100644
index 0000000..210b1d5
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/ResponseUtil.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.server.web.utils;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.json.JSONObject;
+
+/**
+ * Common simple responses of success and failure
+ * 
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ */
+public class ResponseUtil {
+
+    public static void simpleResponse(HttpServletResponse resp, String name ,boolean state) throws IOException {
+        resp.setContentType("application/json");
+        JSONObject object = new JSONObject();
+        object.put(name, state);
+        object.write(resp.getWriter());
+    }
+    
+    public static void objectResponse(HttpServletResponse resp, List<Pair> pairs) throws IOException {
+        resp.setContentType("application/json");
+    	JSONObject object = new JSONObject();
+    	
+    	for(Pair entry: pairs){
+    		object.put(entry.getKey(), entry.getValue().toString());	
+    	}
+    	
+    	object.write(resp.getWriter());
+    }
+    
+    /*
+     * Generic Pair Util for Json response
+     */
+    public static class Pair<V>{
+    	String key;
+    	V value;
+		public Pair(String key, V value) {
+			super();
+			this.key = key;
+			this.value = value;
+		}
+		public String getKey() {
+			return key;
+		}
+		public V getValue() {
+			return value;
+		}
+    	
+    	
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/SimpleImageRetriever.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/SimpleImageRetriever.java
new file mode 100644
index 0000000..e49db4d
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/SimpleImageRetriever.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ */
+
+package pt.ua.dicoogle.server.web.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.core.ServerSettings;
+import pt.ua.dicoogle.plugins.PluginController;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.server.web.dicom.Convert2PNG;
+
+/**
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class SimpleImageRetriever implements ImageRetriever {
+
+    private static final Logger logger = LoggerFactory.getLogger(SimpleImageRetriever.class);
+    
+    @Override
+    public ByteArrayInputStream get(URI uri, int frame, boolean thumbnail) throws IOException {
+        return getPNGStream(fromURI(uri), frame, thumbnail);
+    }
+
+    private static StorageInputStream fromURI(URI uri) throws IOException {
+        StorageInterface storage = PluginController.getInstance().getStorageForSchema(uri);
+        Iterator<StorageInputStream> store = storage.at(uri).iterator();
+        if (!store.hasNext()) {
+            throw new IOException("No storage item found at the given URI");
+        }
+        return store.next();
+    }
+
+    private static ByteArrayInputStream getPNGStream(StorageInputStream imgFile, int frame, boolean thumbnail) throws IOException {
+        ByteArrayOutputStream pngStream;
+        if (thumbnail) {
+            int thumbSize;
+            try {
+                // retrieve thumbnail dimension settings
+                thumbSize = Integer.parseInt(ServerSettings.getInstance().getThumbnailsMatrix());
+            } catch (NumberFormatException ex) {
+                logger.warn("Failed to parse ThumbnailMatrix, using default thumbnail size");
+                thumbSize = 64;
+            }
+            pngStream = Convert2PNG.DICOM2ScaledPNGStream(imgFile, frame, thumbSize, thumbSize);
+        } else {
+            pngStream = Convert2PNG.DICOM2PNGStream(imgFile, frame);
+        }
+        return new ByteArrayInputStream(pngStream.toByteArray());
+    }}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/TreeNode.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/TreeNode.java
new file mode 100644
index 0000000..ea03c15
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/TreeNode.java
@@ -0,0 +1,174 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This is just a helper class to make it a lot easier to add the data onto the
+ * treeview in html form the data gets sent to one of these first.
+ *
+ * @author Antonio
+ */
+public class TreeNode<T>
+{
+	private String name; // the name of this node
+	private T data; // some data attached to it
+
+	private TreeNode<T> parent;
+	private List<TreeNode<T>> children;
+
+	public TreeNode(String name, T data, TreeNode<T> parent)
+	{
+		this.name = name;
+		this.data = data;
+
+		this.parent = parent;
+		this.children = new ArrayList<TreeNode<T>>();
+	}
+
+	/**
+	 * @return the name
+	 */
+	public String getName()
+	{
+		return name;
+	}
+
+	/**
+	 * @param name the name to set
+	 */
+	public void setName(String name)
+	{
+		this.name = name;
+	}
+
+	/**
+	 * @return the data
+	 */
+	public T getData()
+	{
+		return data;
+	}
+
+	/**
+	 * @param data the data to set
+	 */
+	public void setData(T data)
+	{
+		this.data = data;
+	}
+
+	/**
+	 * @return the parent
+	 */
+	public TreeNode<T> getParent()
+	{
+		return parent;
+	}
+
+	/**
+	 * @return the child count
+	 */
+	public int getChildCount()
+	{
+		return children.size();
+	}
+
+	/**
+	 * Returns the i-child.
+	 *
+	 * @param i the index of the child to get.
+	 * @return a TreeNode object or null if i is not a valid index.
+	 */
+	public TreeNode<T> getChild(int i)
+	{
+		// if it's not a valid index return null
+		if ((i < 0) || (i >= children.size()))
+			return null;
+
+		return children.get(i);
+	}
+
+	/**
+	 * Returns the child with the specified name.
+	 *
+	 * @param name the name of the child to get.
+	 * @return a TreeNode object or null if the name is not a valid/found child.
+	 */
+	public TreeNode<T> getChild(String name)
+	{
+		// if there are no children
+		if (children.size() < 1)
+			return null;
+
+		for (TreeNode<T> child : children)
+		{
+			if (child.getName().equals(name))
+				return child;
+		}
+
+		// child not found
+		return null;
+	}
+
+	/**
+	 * Adds a child to this node.
+	 *
+	 * @param name the name of the child.
+	 * @param data the data of the child.
+	 * @return the child inserted.
+	 */
+	public TreeNode<T> addChild(String name, T data)
+	{
+		TreeNode<T> child = new TreeNode<T>(name, data, this);
+		this.children.add(child);
+		return child;
+	}
+
+	/**
+	 * Based on a path-alike set of dir entries, returns the final node of it.
+	 * If the path doesn't exist, it's created.
+	 *
+	 * @param names a set of TreeNode entries.
+	 * @return the last TreeNode of the path.
+	 */
+	public TreeNode<T> getTreeNode(String... names)
+	{
+		TreeNode<T> node = this;
+
+		for (String aName : names)
+		{
+			// get the child node with this name was found
+			TreeNode<T> child = node.getChild(aName);
+
+			// if it was not found the create it
+			if (child == null)
+			{
+				child = node.addChild(aName, null);
+			}
+
+			// now that we are absolutely sure that the child node exists move onto it, so we can continuing parsing the next part of the "path"
+			node = child;
+		}
+
+		return node;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/types/DataTable.java b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/types/DataTable.java
new file mode 100644
index 0000000..ecbd15a
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/server/web/utils/types/DataTable.java
@@ -0,0 +1,306 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.server.web.utils.types;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4;
+import pt.ua.dicoogle.sdk.settings.Utils;
+
+/**
+ * Handles a data (type) that is suposed to be on a table form.
+ * Supports multiple fields, in a String format.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class DataTable
+{
+	/**
+	 * Column names.
+	 */
+	private String[] columns;
+	/**
+	 * Cell data.
+	 */
+	private Object[][] data;
+
+	/**
+	 * Creates a DataTable with no columns nor cells.
+	 */
+	public DataTable()
+	{
+		columns = new String[0];
+		data = new Object[0][0];
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns.
+	 *
+	 * @param columnCount the initial number of columns.
+	 */
+	public DataTable(int columnCount)
+	{
+		columns = new String[columnCount];
+		data = new String[0][columnCount];
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns and (empty) rowCount rows.
+	 * @param columnCount the initial number of columns.
+	 * @param rowCount the initial number of rows.
+	 */
+	public DataTable(int columnCount, int rowCount)
+	{
+		columns = new String[columnCount];
+		data = new Object[rowCount][columnCount];
+	}
+
+	/**
+	 * Returns the column count on this DataTable.
+	 *
+	 * @return the column count on this DataTable.
+	 */
+	public synchronized int getColumnCount()
+	{
+		return columns.length;
+	}
+
+	/**
+	 * Returns the row count on this DataTable.
+	 *
+	 * @return the row count on this DataTable.
+	 */
+	public synchronized int getRowCount()
+	{
+		return data.length;
+	}
+
+	/**
+	 * Validates a column index for later use.
+	 *
+	 * @param index the index (zero based) of the target column.
+	 */
+	public synchronized boolean isValidColumnIndex(int index)
+	{
+		return ((index >= 0) && (index < columns.length));
+	}
+
+	/**
+	 * Validates a cell index for later use.
+	 *
+	 * @param row the row index (zero based) of the target cell.
+	 * @param column the column index (zero based) of the target cell.
+	 */
+	public synchronized boolean isValidCellIndex(int row, int column)
+	{
+		return (isValidColumnIndex(column) && ((row >= 0) && (row < data.length)));
+	}
+
+	/**
+	 * Adds a new (unamed) column at the end of the column list.
+	 */
+	public synchronized void addColumn()
+	{
+		// create a bigger sized array
+		String[] newColumns = new String[columns.length + 1];
+		Object[][] newData = new Object[data.length][columns.length + 1];
+
+		// copy all the previous data
+		System.arraycopy(columns, 0, newColumns, 0, columns.length);
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// set the new data as the current one
+		columns = newColumns;
+		data = newData;
+	}
+
+	/**
+	 * Adds a new column at the end of the column list.
+	 *
+	 * @param name the name/title of the new column.
+	 */
+	public synchronized void addColumn(String name)
+	{
+		// create a bigger sized array
+		String[] newColumns = new String[columns.length + 1];
+		Object[][] newData = new Object[data.length][columns.length + 1];
+
+		// copy all the previous data
+		System.arraycopy(columns, 0, newColumns, 0, columns.length);
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// add the new data
+		newColumns[columns.length] = name;
+
+		// set the new data as the current one
+		columns = newColumns;
+		data = newData;
+	}
+
+	/**
+	 * Changes the selected column name to the desired one.
+	 * Gracefully aborts if the the column index is not valid.
+	 *
+	 * @param column the index (zero based) of the target column.
+	 * @param name the desired new name for the column.
+	 */
+	public synchronized void setColumnName(int column, String name)
+	{
+		if (! isValidColumnIndex(column))
+			return;
+
+		columns[column] = name;
+	}
+
+	/**
+	 * Adds a new (empty) row at the end of the table.
+	 */
+	public synchronized void addRow()
+	{
+		// create a bigger sized array
+		Object[][] newData = new Object[data.length + 1][columns.length];
+
+		// copy all the previous data
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// set the new data as the current one
+		data = newData;
+	}
+
+	/**
+	 * Changes the selected cell data to the desired one.
+	 * Gracefully aborts if the the cell location is not valid.
+	 *
+	 * @param row the row index (zero based) of the target cell.
+	 * @param column the column index (zero based) of the target cell.
+	 * @param data the new data for the target cell.
+	 */
+	public synchronized void setCellData(int row, int column, Object data)
+	{
+		if (! isValidCellIndex(row, column))
+			return;
+
+		this.data[row][column] = data;
+	}
+
+	// Output formats ------------------------------------------------------
+
+	public synchronized String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<div id=\"" + htmlElementID + "\">";
+
+		// loop through all the rows and add their cell data and column name to the result
+		for (int row = 0; row < data.length; row++)
+		{
+			result += "<div class=\"data-table-row\">";
+
+			for (int column = 0; column < columns.length; column++)
+			{
+				String columnID = Utils.getHTMLElementIDFromString(columns[column]);
+
+				result += escapeHtml4(columns[column]) + " " + Utils.getHTMLInputFromType(columnID, data[row][column], true);
+
+				result += "   ";
+			}
+
+			// add a button to remove each element, except the first one
+			result += 	"<button type=\"button\" class=\"removeButton\" onclick=\"removeDataTableRow(this.parentNode.parentNode, this.parentNode);\" " + ((row == 0) ? "hidden" : "") + ">Remove</button>";
+
+			result += "</div>";
+		}
+
+		result += "</div>";
+
+		// add one button to add another element to the table
+		result += "<button type=\"button\" onclick=\"addDataTableRow(document.getElementById('" + htmlElementID + "'));\">Add</button><br />"; // FIXME replace the getelementbyid with this.previoussibling ?!? http://www.w3schools.com/dom/prop_element_previoussibling.asp
+
+		return result;
+	}
+	
+	
+
+	// Input formats -------------------------------------------------------
+
+	@Override
+	public String toString() {
+		return toHTMLString("PID---");
+				}
+
+	/**
+	 * Based on a list of http request form (names & values) and a original value object,
+	 * parse the first ones to match the second ones format with the new values.
+	 *
+	 * @param original the original DataTable.
+	 * @param params the new params, and their values, to put into the DataTable.
+	 * @return a new DataTable with the updated cell information.
+	 */
+	public static DataTable fromHTTPParams(DataTable original, HashMap<String, String[]> params)
+	{
+		// find how many rows the new params have list has
+		int paramsCountMin = Integer.MAX_VALUE;
+		int paramsCountMax = Integer.MIN_VALUE;
+		for (String[] list : params.values())
+		{
+			if (list.length < paramsCountMin)
+				paramsCountMin = list.length;
+			if (list.length > paramsCountMax)
+				paramsCountMax = list.length;
+		}
+
+		// create a new DataTable with the same column size as the original one and the same row count as the new params
+		DataTable result = new DataTable(original.getColumnCount(), paramsCountMax);
+
+		// add all the columns titles/names
+		for (int i = 0; i < result.getColumnCount(); i++)
+			result.setColumnName(i, original.columns[i]);
+
+		// add all the cells information present on the original DataTable
+		for (int j = 0; j < result.getColumnCount(); j++)
+		{
+			String columnID = Utils.getHTMLElementIDFromString(result.columns[j]);
+			boolean hasNewValues = params.containsKey(columnID);
+
+			for (int i = 0; i < result.getRowCount(); i++)
+			{
+				Object cellData = original.data[i][j];
+
+				// if there is a new value for this cell then use it
+				if (hasNewValues)
+				{
+					cellData = Utils.convertStringValueIntoProperType(cellData, params, i, columnID);
+					// FIMXE if paramsCountMax is different of paramsCountMin them some column might not have all param values
+					//	this is true if boolean column are used, but browsers don't usually report back the uncheked boxes
+					//	so extra logic must be applied to fix this issue with boolean values
+					//	the problem relies on how do we know in what row is the value missing?
+				}
+
+				result.setCellData(j, j, cellData);
+			}
+		}
+
+		// return the newly formed DataTable
+		return result;
+	}
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/RunningIndexTasks.java b/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/RunningIndexTasks.java
new file mode 100644
index 0000000..cc59472
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/RunningIndexTasks.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.taskManager;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.datastructs.IndexReport;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * Singleton that contains all running index tasks
+ *
+ * @author Frederico Silva <fredericosilva at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class RunningIndexTasks {
+    private static final Logger logger = LoggerFactory.getLogger(RunningIndexTasks.class);
+    
+	public static RunningIndexTasks instance;
+
+	private final Map<String, Task<Report>> taskRunningList;
+
+	public static RunningIndexTasks getInstance() {
+		if (instance == null)
+			instance = new RunningIndexTasks();
+
+		return instance;
+	}
+
+	public RunningIndexTasks() {
+		taskRunningList = new HashMap<>();
+	}
+
+	public void addTask(String taskUid, Task<Report> task) {
+		taskRunningList.put(taskUid, task);
+	}
+
+	public boolean removeTask(String taskUid) {
+		return taskRunningList.remove(taskUid) != null;
+	}
+
+	public boolean stopTask(String taskUid) {
+		Task<Report> task = taskRunningList.get(taskUid);
+		if (task != null) {
+			return task.cancel(true);
+		} else {
+			logger.info("Attempt to stop unexistent task {}, ignoring", taskUid);
+		}
+
+		return false;
+	}
+
+	public Map<String, Task<Report>> getRunningTasks() {
+
+		return taskRunningList;
+	}
+
+    public String toJson() {
+        JSONObject object = new JSONObject();
+        JSONArray array = new JSONArray();
+
+        int countComplete = 0;
+        int countCancelled = 0;
+        for (Map.Entry<String, Task<Report>> pair : taskRunningList.entrySet()) {
+            Task<Report> task = pair.getValue();
+            JSONObject entry = new JSONObject();
+            entry.put("taskUid", pair.getKey());
+            entry.put("taskName", task.getName());
+            entry.put("taskProgress", task.getProgress());
+
+            if (task.isDone() && !task.isCancelled()) {
+                entry.put("complete", true);
+                countComplete += 1;
+                try {
+                    Report r = task.get();
+                    if (r instanceof IndexReport) {
+                        entry.put("elapsedTime", ((IndexReport)r).getElapsedTime());
+                        entry.put("nIndexed", ((IndexReport)r).getNIndexed());
+                        entry.put("nErrors", ((IndexReport)r).getNErrors());
+                    }
+                } catch (InterruptedException | ExecutionException ex) {
+                    logger.warn("Could not retrieve task result, ignoring", ex);
+                }
+            }
+            if (task.isCancelled()) {
+                countCancelled += 1;
+                entry.put("canceled", true);
+            }
+            array.add(entry);
+        }
+
+        object.put("results", array);
+        object.put("count", array.size() - countComplete - countCancelled);
+        return object.toString();
+    }
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/TaskManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/TaskManager.java
new file mode 100644
index 0000000..db36153
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/taskManager/TaskManager.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.taskManager;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * 
+ * This is a task manager for Dicoogle.
+ * Currently it is based on a fixed thread pool executor with a maximum of 4 threads executing simultaneously. 
+ * 
+ * TODO: change interface to use generics.
+ * 
+ * @author psytek
+ */
+public class TaskManager {
+    ExecutorService taskExecutor;
+    int nConcurrentThreads = 3;
+    
+    public TaskManager(){
+        taskExecutor = Executors.newFixedThreadPool(nConcurrentThreads);
+    }
+    
+    public TaskManager(int nConcurrentThreads){
+        this.nConcurrentThreads = nConcurrentThreads;
+        taskExecutor = Executors.newFixedThreadPool(nConcurrentThreads);
+    }
+    
+    /**asynch execution of a task*/
+    public void dispatch(Task<?> t){
+        taskExecutor.submit(t);
+    }
+    
+    
+
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/utils/CPULoad.java b/dicoogle/src/main/java/pt/ua/dicoogle/utils/CPULoad.java
new file mode 100755
index 0000000..62aa0b3
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/utils/CPULoad.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.utils;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.ThreadMXBean;
+import java.util.Date;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class CPULoad
+{
+
+
+    public CPULoad()
+    {
+
+    }
+
+    public double cpuLoad()
+    {
+
+        ThreadMXBean TMB = ManagementFactory.getThreadMXBean();
+        long time = new Date().getTime() * 1000000;
+        long cput = 0;
+        double cpuperc = -1;
+
+        //Begin loop.
+
+        if( TMB.isThreadCpuTimeSupported() )
+        {
+                if(new Date().getTime() * 1000000 - time > 1000000000) //Reset once per second
+                {
+                        time = new Date().getTime() * 1000000;
+                        cput = TMB.getCurrentThreadCpuTime();
+                }
+
+                if(!TMB.isThreadCpuTimeEnabled())
+                {
+                        TMB.setThreadCpuTimeEnabled(true);
+                }
+
+                if(new Date().getTime() * 1000000 - time != 0)
+                        cpuperc = (TMB.getCurrentThreadCpuTime() - cput) / (new Date().getTime() * 1000000.0 - time) * 100.0;
+            }
+        else
+        {
+            cpuperc = -2;
+        }
+
+        return cpuperc;
+
+    }
+
+    public static double getAvgCpu()
+    {
+        OperatingSystemMXBean osBean=ManagementFactory.getOperatingSystemMXBean();
+        return osBean.getSystemLoadAverage();
+    }
+
+
+
+    
+    
+
+    
+
+}
+
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/utils/Dicom2JPEG.java b/dicoogle/src/main/java/pt/ua/dicoogle/utils/Dicom2JPEG.java
new file mode 100755
index 0000000..1e84d99
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/utils/Dicom2JPEG.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.utils;
+
+//import com.sun.image.codec.jpeg.JPEGCodec;
+//import com.sun.image.codec.jpeg.JPEGImageEncoder;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.Iterator;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+import org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam;
+
+/**
+ *
+ * @author Carlos Costa
+ */
+public class Dicom2JPEG {
+    
+    public static boolean convertDicom2Jpeg(File dcmFile, File jpgFile){
+        return convertDicom2Jpeg(dcmFile, jpgFile, 0);
+    }
+    
+    public static boolean convertDicom2Jpeg(File dcmFile, File jpgFile, int scaleHeight){
+        try {
+            return convertDicom2Jpeg(dcmFile, new BufferedOutputStream(new FileOutputStream(jpgFile)), scaleHeight);
+        } catch (FileNotFoundException ex) {
+            System.out.println("\nError: can not write to JPG file!"+ ex.getMessage());
+        }
+        
+        return false;
+    }
+    
+    public static boolean convertDicom2Jpeg(File dcmFile, OutputStream jpgStream){
+        return convertDicom2Jpeg(dcmFile, jpgStream, 0);
+    }
+    
+    public static boolean convertDicom2Jpeg(File dcmFile, OutputStream jpgStream, int scaleHeight){
+        boolean result = false;
+        ByteArrayOutputStream jpgMem = Dicom2MemJPEG(dcmFile, scaleHeight);
+        
+        if (jpgMem != null){
+            try {
+                jpgMem.writeTo(jpgStream);
+                jpgStream.close();
+                result = true;
+            } 
+            catch(IOException e) {
+                System.out.println("\nError: can not write to JPG file!"+ e.getMessage());
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    
+    public static ByteArrayOutputStream Dicom2MemJPEG(File dcmFile){
+        return Dicom2MemJPEG(dcmFile, 0);
+    }
+        
+    public static ByteArrayOutputStream Dicom2MemJPEG(File dcmFile, int scaleHeight){
+        //File myDicomFile = new File("c:/dicomImage.dcm");
+        BufferedImage myJpegImage = null;
+        
+        // returns an Iterator containing all currently registered ImageReaders 
+        // that claim to be able to decode the named format 
+        // (e.g., "DICOM", "jpeg", "tiff")
+        Iterator iter = ImageIO.getImageReadersByFormatName("DICOM");  
+        ImageReader reader = (ImageReader) iter.next();
+        DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();
+        
+        try {
+            ImageInputStream iis = ImageIO.createImageInputStream(dcmFile);
+            reader.setInput(iis, false); 
+            myJpegImage = reader.read(0, param); 
+            iis.close();
+
+            if (myJpegImage == null) {
+                System.out.println("\nError: couldn't read dicom image!");
+                return null;
+            }
+            
+
+            // Resize Image -> Thumbnails....
+            if (scaleHeight > 0){
+                if (scaleHeight < 24) 
+                    scaleHeight = 24; // minimum
+                myJpegImage = getScaledImageWithHeight(myJpegImage, scaleHeight);           
+            }
+                    
+            //OutputStream output = new BufferedOutputStream(new FileOutputStream(jpgFile));
+            ByteArrayOutputStream jpgArray = new ByteArrayOutputStream();
+            OutputStream output = new BufferedOutputStream(jpgArray); 
+            
+            //JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(output);
+            //encoder.encode(myJpegImage);
+            output.close();             // Has no effect to ByteArrayOutputStream
+            
+            return jpgArray;
+        } 
+        catch(IOException e) {
+            System.out.println("\nError: couldn't read dicom image!"+ e.getMessage());
+            return null;
+        }
+        catch(Exception e) {
+            System.out.println("\nError: "+ e.getMessage());
+            return null;
+        }
+    }
+    
+    
+    /**A method that scales a Buffered image and takes the required height as a refference point**/
+    public static BufferedImage getScaledImageWithHeight(BufferedImage image, int height) throws java.lang.Exception {
+        int width = (int) (((float) image.getWidth() / (float) image.getHeight()) * height);
+
+        Image scaledImage = image.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH);
+        BufferedImage outImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2 = (Graphics2D) outImage.createGraphics();
+        g2.drawImage(scaledImage, 0, 0, null);
+
+        return outImage;
+    }
+    
+}
diff --git a/dicoogle/src/main/java/pt/ua/dicoogle/utils/KeysManager.java b/dicoogle/src/main/java/pt/ua/dicoogle/utils/KeysManager.java
new file mode 100755
index 0000000..ee4e7f4
--- /dev/null
+++ b/dicoogle/src/main/java/pt/ua/dicoogle/utils/KeysManager.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.utils;
+
+import java.io.BufferedOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class KeysManager
+{
+    private static final String LOCAL_PATH = "Server_Keystore";
+    
+    public static String getServerKeyPath()
+    {
+        File keyPath = new File(LOCAL_PATH);
+        if(keyPath.exists() && keyPath.canRead()){
+            return keyPath.getAbsolutePath();        
+        }
+        
+        //COPY FILE FROM JAR
+        InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Server_Keystore");
+        if (stream!=null)
+        {            
+            try
+            {
+                DataOutputStream out = new DataOutputStream(
+                        new BufferedOutputStream(
+                        new FileOutputStream(keyPath)));
+                int c;
+                while((c = stream.read()) != -1)
+                {
+                        out.writeByte(c);
+                }
+                stream.close();
+                out.close();
+            }
+            catch(IOException e)
+            {
+                System.err.println("Error Writing/Reading Streams.");
+            }
+        }
+        else
+        {
+            //DebugManager.getInstance().debug("Missing the KeyStore file that contains the SSL keys of server");
+            System.err.println("Missing the KeyStore file that contains the SSL keys of server");
+        }
+    
+        return keyPath.getAbsolutePath();
+}
+
+
+    public static String getClientKeyPath()
+    {
+        File keyPath = new File(LOCAL_PATH);
+        if(keyPath.exists() && keyPath.canRead()){
+            return keyPath.getAbsolutePath();        
+        }
+
+        //Last shot
+        InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Client_Truststore");
+            
+        if (stream!=null)
+        {
+            try
+            {
+                DataOutputStream out = new DataOutputStream(
+                        new BufferedOutputStream(
+                        new FileOutputStream(keyPath)));
+                int c;
+                while((c = stream.read()) != -1)
+                {
+                        out.writeByte(c);
+                }
+                stream.close();
+                out.close();
+
+            }
+            catch(IOException e)
+            {
+                    System.err.println("Error Writing/Reading Streams.");
+            }
+        }
+        else
+        {
+            //DebugManager.getInstance().debug("Missing the TrustStore file that confirms the server certificate");
+            System.err.println("Missing the TrustStore file that confirms the server certificate");
+            System.exit(-3);
+        }
+    
+
+    return keyPath.getAbsolutePath();
+    }
+}
diff --git a/dicoogle/src/main/resources/log4j2.xml b/dicoogle/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..08799eb
--- /dev/null
+++ b/dicoogle/src/main/resources/log4j2.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <Console name="STDOUT" target="SYSTEM_OUT">
+            <PatternLayout pattern="%-5p %C{2} (%F:%L) - %m%n"/>
+        </Console>
+        <RollingRandomAccessFile name="Rolling" fileName="dicoogle.log" filePattern="dicoogle-%i.log" >
+            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} | %-5p [%t] (%F:%L) - %m%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy />
+                <SizeBasedTriggeringPolicy size="2.0 MB"/>
+            </Policies>
+        </RollingRandomAccessFile>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="STDOUT" level="info" />
+            <AppenderRef ref="Rolling" level="info" />
+        </Root>
+        <Logger name="pt.ua.dicoogle" level="info" additivity="false">
+            <AppenderRef ref="STDOUT" />
+            <AppenderRef ref="Rolling" />
+        </Logger>
+        <Logger name="org.eclipse.jetty" additivity="false">
+            <AppenderRef ref="STDOUT" level="warn" />
+            <AppenderRef ref="Rolling" level="info" />
+        </Logger>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/log4j2_sentry.xml b/dicoogle/src/main/resources/log4j2_sentry.xml
new file mode 100644
index 0000000..4bcfded
--- /dev/null
+++ b/dicoogle/src/main/resources/log4j2_sentry.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration packages="org.apache.logging.log4j.core,net.kencochrane.raven.log4j2">
+    <Appenders>
+        <Console name="STDOUT" target="SYSTEM_OUT">
+            <PatternLayout pattern="%-5p %C{2} (%F:%L) - %m%n"/>
+        </Console>
+        <RollingRandomAccessFile name="Rolling" fileName="dicoogle.log" filePattern="dicoogle-%i.log" >
+            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} | %-5p [%t] %C{2} (%F:%L) - %m%n"/>
+            <Policies>
+                <OnStartupTriggeringPolicy />
+                <SizeBasedTriggeringPolicy size="2.0 MB"/>
+            </Policies>
+        </RollingRandomAccessFile>
+        <Raven name="Sentry">
+            <dsn>
+                <!-- fill in the address before using -->
+                https://publicKey:secretKey@host:port/1?options
+            </dsn>
+            <tags>
+            </tags>
+            <!--
+                Optional, allows to select the ravenFactory
+            -->
+            <!--
+            <ravenFactory>
+                net.kencochrane.raven.DefaultRavenFactory
+            </ravenFactory>
+            -->
+        </Raven>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="STDOUT" />
+            <AppenderRef ref="Rolling" />
+            <AppenderRef ref="Sentry" level="error" />
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/version.txt b/dicoogle/src/main/resources/version.txt
new file mode 100644
index 0000000..50f898a
--- /dev/null
+++ b/dicoogle/src/main/resources/version.txt
@@ -0,0 +1 @@
+${project.version}-${buildNumber}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/.eslintrc b/dicoogle/src/main/resources/webapp/.eslintrc
new file mode 100644
index 0000000..28fca90
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/.eslintrc
@@ -0,0 +1,81 @@
+{
+  "extends": [
+    "eslint:recommended"
+  ],
+  "parser": "babel-eslint",
+  "parserOptions": {
+    "ecmaVersion": 6,
+    "sourceType": "module",
+    "ecmaFeatures": {
+      "modules": true,
+      "jsx": true
+    }
+  },
+  "env": {
+    "browser": true,
+    "commonjs": true,
+    "es6": true
+  },
+  "globals": {
+    "process": false
+  },
+  "plugins": [
+    "react",
+    "import"
+  ],
+  "settings": {
+    "import/resolver": {
+      "node": {
+        "extensions": [".js", ".jsx"]
+      }
+    },
+    "react": {
+      "pragma": "React",
+      "version": "0.14"
+    }
+  },
+  "rules": {
+    "no-console": 0,
+    "quotes": 0,
+    "camelcase": 0,
+    "curly": 0,
+    "new-cap": 0,
+    "no-trailing-spaces": 0,
+    "eqeqeq": 1,
+    "no-alert": 1,
+    "key-spacing": 1,
+    "no-unused-vars": [1, {"vars": "all", "args": "none"}],
+    "comma-spacing": 1,
+    "space-infix-ops": 1,
+    "no-mixed-spaces-and-tabs": 1,
+    "no-multi-spaces": 1,
+    "semi-spacing": 1,
+    "comma-dangle": 1,
+    "no-extra-semi": 1,
+    "eol-last": 1,
+    "no-empty": 1,
+    "no-dupe-args": 2,
+    "no-dupe-keys": 2,
+    "no-undef": 2,
+    "import/no-unresolved": [2, {"commonjs": true}],
+    "import/named": 2,
+    "import/namespace": 2,
+    "import/default": 2,
+    "import/export": 2,
+    "import/no-extraneous-dependencies": 1,
+    "import/no-mutable-exports": 1,
+    "react/jsx-no-duplicate-props": 2,
+    "react/jsx-no-undef": 2,
+    "react/jsx-uses-react": 2,
+    "react/jsx-uses-vars": 2,
+    "react/no-danger": 2,
+    "react/no-direct-mutation-state": 2,
+    "react/no-unknown-property": 2,
+    "react/react-in-jsx-scope": 2,
+    "react/no-deprecated": 1,
+    "react/no-did-mount-set-state": 1,
+    "react/no-did-update-set-state": 1,
+    "react/jsx-boolean-value": 1,
+    "react/no-is-mounted": 0
+  }
+}
diff --git a/dicoogle/src/main/resources/webapp/.gitignore b/dicoogle/src/main/resources/webapp/.gitignore
new file mode 100644
index 0000000..d90cd5e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/.gitignore
@@ -0,0 +1,4 @@
+/index.html
+/css/dicoogle.css
+/css/dicoogle.css.map
+/lib/
diff --git a/dicoogle/src/main/resources/webapp/README.md b/dicoogle/src/main/resources/webapp/README.md
new file mode 100644
index 0000000..1d9a02e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/README.md
@@ -0,0 +1,79 @@
+# Dicoogle Web Application
+
+## Building
+
+`npm` version 2 or earlier is required. To build everything for production (ready to be bundled for when creating dicoogle.jar):
+
+    npm install
+
+To build all js and html resources:
+
+    npm run debug        # for development
+    npm run build        # for production
+
+To build just the css files:
+
+    npm run css
+
+To watch for changes in JavaScript resources (good for building while developing):
+
+    npm run js:watch
+
+To watch for changes in the SASS resources (thus building css):
+
+    npm run css:watch
+
+Everything is build for production (js, html and css) in the prepublish script (this is also run automatically for `npm install`):
+
+    npm run-script prepublish
+
+All of these npm scripts map directly to gulp tasks:
+
+```bash
+$ gulp --tasks
+
+ ├── lint
+ ├─┬ js
+ │ └── lint
+ ├─┬ js-debug
+ │ └── lint
+ ├── js:watch
+ ├── html
+ ├── html-debug
+ ├── css
+ ├── css-debug
+ ├── css:watch
+ ├─┬ production
+ │ ├── js
+ │ ├── html
+ │ └── css
+ ├─┬ development
+ │ ├── js-debug
+ │ ├── html-debug
+ │ └── css
+ ├── clean
+ └─┬ default
+   └── production
+```
+
+## Running as a standalone server
+
+We have included a script for running a static server containing the standalone webapp. If you already have Python installed, simply execute:
+
+    ./run_server
+
+## Debugging the webapp
+
+The web application can be tested separately without having it embedded in a jar file. The steps are simple:
+
+1. Start Dicoogle, locally or on a server: `java -jar dicoogle.jar -s`. The jar file does not need to contain the web application in this case. You may also need to change your configuration in the config.xml file, so as to enable cross-origin requests:
+
+```xml
+<server enable="true" port="8080" allowedOrigins="*" />
+```
+
+2. Navigate to the webapp's source code. Define the URL to Dicoogle's base endpoint using the `DICOOGLE_BASE_URL` environment variable, and bundle the source code: `DICOOGLE_BASE_URL=http://localhost:8080 npm run debug`. See the **Building** section above for more scripts.
+
+3. Start a static server on the web application's base folder. If you have Python, the `run_server` script will do.
+
+4. Open your browser and navigate to the static server: http://localhost:9000
diff --git a/dicoogle/src/main/resources/webapp/assets/drawer_menu.png b/dicoogle/src/main/resources/webapp/assets/drawer_menu.png
new file mode 100644
index 0000000..0ccbfe8
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/drawer_menu.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/favicon.ico b/dicoogle/src/main/resources/webapp/assets/favicon.ico
new file mode 100644
index 0000000..5dec3b3
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/favicon.ico differ
diff --git a/dicoogle/src/main/resources/webapp/assets/image-not-found.png b/dicoogle/src/main/resources/webapp/assets/image-not-found.png
new file mode 100644
index 0000000..712f094
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/image-not-found.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logo.png b/dicoogle/src/main/resources/webapp/assets/logo.png
new file mode 100644
index 0000000..6818372
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logo.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logos/logo-ieeta.png b/dicoogle/src/main/resources/webapp/assets/logos/logo-ieeta.png
new file mode 100644
index 0000000..3c51456
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logos/logo-ieeta.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logos/logo-ua.png b/dicoogle/src/main/resources/webapp/assets/logos/logo-ua.png
new file mode 100644
index 0000000..fb7eebb
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logos/logo-ua.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logos/logo.png b/dicoogle/src/main/resources/webapp/assets/logos/logo.png
new file mode 100644
index 0000000..b025e0d
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logos/logo.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logos/logoFCT.png b/dicoogle/src/main/resources/webapp/assets/logos/logoFCT.png
new file mode 100644
index 0000000..c158fcd
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logos/logoFCT.png differ
diff --git a/dicoogle/src/main/resources/webapp/assets/logos/logobio.png b/dicoogle/src/main/resources/webapp/assets/logos/logobio.png
new file mode 100644
index 0000000..00856de
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/assets/logos/logobio.png differ
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422916890.css b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422916890.css
new file mode 100644
index 0000000..4c3e7ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422916890.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-dange [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917240.css b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917240.css
new file mode 100644
index 0000000..4c3e7ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917240.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-dange [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917712.css b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917712.css
new file mode 100644
index 0000000..4c3e7ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917712.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-dange [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917766.css b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917766.css
new file mode 100644
index 0000000..4c3e7ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap-theme.min_1422917766.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-dange [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap_1422916890.css b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap_1422916890.css
new file mode 100644
index 0000000..c6f3d21
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/_pgbackup/bootstrap_1422916890.css
@@ -0,0 +1,6332 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+html {
+  font-family: sans-serif;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background-color: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  margin: .67em 0;
+  font-size: 2em;
+}
+mark {
+  color: #000;
+  background: #ff0;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+sup {
+  top: -.5em;
+}
+sub {
+  bottom: -.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  height: 0;
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  margin: 0;
+  font: inherit;
+  color: inherit;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+  -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  padding: .35em .625em .75em;
+  margin: 0 2px;
+  border: 1px solid #c0c0c0;
+}
+legend {
+  padding: 0;
+  border: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-spacing: 0;
+  border-collapse: collapse;
+}
+td,
+th {
+  padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+ at media print {
+  *,
+  *:before,
+  *:after {
+    color: #000 !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    -webkit-box-shadow: none !important;
+            box-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  select {
+    background: #fff !important;
+  }
+  .navbar {
+    display: none;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+ at font-face {
+  font-family: 'Glyphicons Halflings';
+
+  src: url('../fonts/glyphicons-halflings-regular.eot');
+  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\2a";
+}
+.glyphicon-plus:before {
+  content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+* {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #333;
+  background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #337ab7;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #23527c;
+  text-decoration: underline;
+}
+a:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 6px;
+}
+.img-thumbnail {
+  display: inline-block;
+  max-width: 100%;
+  height: auto;
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: all .2s ease-in-out;
+       -o-transition: all .2s ease-in-out;
+          transition: all .2s ease-in-out;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+  border: 0;
+  border-top: 1px solid #eee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 20px;
+  margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 36px;
+}
+h2,
+.h2 {
+  font-size: 30px;
+}
+h3,
+.h3 {
+  font-size: 24px;
+}
+h4,
+.h4 {
+  font-size: 18px;
+}
+h5,
+.h5 {
+  font-size: 14px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 10px;
+}
+.lead {
+  margin-bottom: 20px;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+ at media (min-width: 768px) {
+  .lead {
+    font-size: 21px;
+  }
+}
+small,
+.small {
+  font-size: 85%;
+}
+mark,
+.mark {
+  padding: .2em;
+  background-color: #fcf8e3;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777;
+}
+.text-primary {
+  color: #337ab7;
+}
+a.text-primary:hover {
+  color: #286090;
+}
+.text-success {
+  color: #3c763d;
+}
+a.text-success:hover {
+  color: #2b542c;
+}
+.text-info {
+  color: #31708f;
+}
+a.text-info:hover {
+  color: #245269;
+}
+.text-warning {
+  color: #8a6d3b;
+}
+a.text-warning:hover {
+  color: #66512c;
+}
+.text-danger {
+  color: #a94442;
+}
+a.text-danger:hover {
+  color: #843534;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #337ab7;
+}
+a.bg-primary:hover {
+  background-color: #286090;
+}
+.bg-success {
+  background-color: #dff0d8;
+}
+a.bg-success:hover {
+  background-color: #c1e2b3;
+}
+.bg-info {
+  background-color: #d9edf7;
+}
+a.bg-info:hover {
+  background-color: #afd9ee;
+}
+.bg-warning {
+  background-color: #fcf8e3;
+}
+a.bg-warning:hover {
+  background-color: #f7ecb5;
+}
+.bg-danger {
+  background-color: #f2dede;
+}
+a.bg-danger:hover {
+  background-color: #e4b9b9;
+}
+.page-header {
+  padding-bottom: 9px;
+  margin: 40px 0 20px;
+  border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  margin-left: -5px;
+  list-style: none;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-right: 5px;
+  padding-left: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+ at media (min-width: 768px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    overflow: hidden;
+    clear: left;
+    text-align: right;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 10px 20px;
+  margin: 0 0 20px;
+  font-size: 17.5px;
+  border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  text-align: right;
+  border-right: 5px solid #eee;
+  border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+address {
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 4px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #fff;
+  background-color: #333;
+  border-radius: 3px;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  font-weight: bold;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #333;
+  word-break: break-all;
+  word-wrap: break-word;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+ at media (min-width: 768px) {
+  .container {
+    width: 750px;
+  }
+}
+ at media (min-width: 992px) {
+  .container {
+    width: 970px;
+  }
+}
+ at media (min-width: 1200px) {
+  .container {
+    width: 1170px;
+  }
+}
+.container-fluid {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+.row {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11,  [...]
+  position: relative;
+  min-height: 1px;
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0;
+}
+ at media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0;
+  }
+}
+ at media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0;
+  }
+}
+ at media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0;
+  }
+}
+table {
+  background-color: transparent;
+}
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #ddd;
+}
+.table .table {
+  background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-child(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  display: table-column;
+  float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  display: table-cell;
+  float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc;
+}
+.table-responsive {
+  min-height: .01%;
+  overflow-x: auto;
+}
+ at media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 15px;
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #ddd;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: inherit;
+  color: #333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 34px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #999;
+}
+.form-control::-webkit-input-placeholder {
+  color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+  background-color: #eee;
+  opacity: 1;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+ at media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"],
+  input[type="time"],
+  input[type="datetime-local"],
+  input[type="month"] {
+    line-height: 34px;
+  }
+  input[type="date"].input-sm,
+  input[type="time"].input-sm,
+  input[type="datetime-local"].input-sm,
+  input[type="month"].input-sm {
+    line-height: 30px;
+  }
+  input[type="date"].input-lg,
+  input[type="time"].input-lg,
+  input[type="datetime-local"].input-lg,
+  input[type="month"].input-lg {
+    line-height: 46px;
+  }
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 20px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-top: 4px \9;
+  margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  vertical-align: middle;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-sm,
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-sm,
+select.form-group-sm .form-control {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+textarea.form-group-sm .form-control,
+select[multiple].input-sm,
+select[multiple].form-group-sm .form-control {
+  height: auto;
+}
+.input-lg,
+.form-group-lg .form-control {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-lg,
+select.form-group-lg .form-control {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-lg,
+textarea.form-group-lg .form-control,
+select[multiple].input-lg,
+select[multiple].form-group-lg .form-control {
+  height: auto;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 42.5px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px;
+}
+.input-sm + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d;
+}
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+  border-color: #2b542c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #3c763d;
+}
+.has-success .form-control-feedback {
+  color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b;
+}
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+  border-color: #66512c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #8a6d3b;
+}
+.has-warning .form-control-feedback {
+  color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442;
+}
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+  border-color: #843534;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #a94442;
+}
+.has-error .form-control-feedback {
+  color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #737373;
+}
+ at media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .form-control-static {
+    display: inline-block;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  padding-top: 7px;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 27px;
+}
+.form-horizontal .form-group {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+ at media (min-width: 768px) {
+  .form-horizontal .control-label {
+    padding-top: 7px;
+    margin-bottom: 0;
+    text-align: right;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 15px;
+}
+ at media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 14.3px;
+  }
+}
+ at media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+  }
+}
+.btn {
+  display: inline-block;
+  padding: 6px 12px;
+  margin-bottom: 0;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: middle;
+  -ms-touch-action: manipulation;
+      touch-action: manipulation;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+  color: #333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  pointer-events: none;
+  cursor: not-allowed;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+          box-shadow: none;
+  opacity: .65;
+}
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus,
+.btn-default.focus,
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default .badge {
+  color: #fff;
+  background-color: #333;
+}
+.btn-primary {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary.focus,
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.btn-success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success:hover,
+.btn-success:focus,
+.btn-success.focus,
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.btn-info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info:hover,
+.btn-info:focus,
+.btn-info.focus,
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.btn-warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning.focus,
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.btn-danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger.focus,
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+.btn-link {
+  font-weight: normal;
+  color: #337ab7;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #23527c;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity .15s linear;
+       -o-transition: opacity .15s linear;
+          transition: opacity .15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+  visibility: hidden;
+}
+.collapse.in {
+  display: block;
+  visibility: visible;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-timing-function: ease;
+       -o-transition-timing-function: ease;
+          transition-timing-function: ease;
+  -webkit-transition-duration: .35s;
+       -o-transition-duration: .35s;
+          transition-duration: .35s;
+  -webkit-transition-property: height, visibility;
+       -o-transition-property: height, visibility;
+          transition-property: height, visibility;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px solid;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  font-size: 14px;
+  text-align: left;
+  list-style: none;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .15);
+  border-radius: 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  color: #262626;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  background-color: #337ab7;
+  outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu-left {
+  right: auto;
+  left: 0;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  content: "";
+  border-top: 0;
+  border-bottom: 4px solid;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 1px;
+}
+ at media (min-width: 768px) {
+  .navbar-right .dropdown-menu {
+    right: 0;
+    left: auto;
+  }
+  .navbar-right .dropdown-menu-left {
+    right: auto;
+    left: 0;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child > .btn:last-child,
+.btn-group > .btn-group:first-child > .dropdown-toggle {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child > .btn:first-child {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-right: 8px;
+  padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-right: 12px;
+  padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+  border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  display: table-cell;
+  float: none;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none;
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555;
+  text-align: center;
+  background-color: #eee;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 3px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 18px;
+  border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  margin-left: -1px;
+}
+.nav {
+  padding-left: 0;
+  margin-bottom: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.nav > li.disabled > a {
+  color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777;
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eee;
+  border-color: #337ab7;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555;
+  cursor: default;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+ at media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+ at media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 4px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #fff;
+  background-color: #337ab7;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+ at media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+ at media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+  visibility: hidden;
+}
+.tab-content > .active {
+  display: block;
+  visibility: visible;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 50px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+}
+ at media (min-width: 768px) {
+  .navbar {
+    border-radius: 4px;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  padding-right: 15px;
+  padding-left: 15px;
+  overflow-x: visible;
+  -webkit-overflow-scrolling: touch;
+  border-top: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+ at media (min-width: 768px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+    visibility: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-right: 0;
+    padding-left: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+ at media (max-device-width: 480px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+ at media (min-width: 768px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+ at media (min-width: 768px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+}
+ at media (min-width: 768px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  height: 50px;
+  padding: 15px 15px;
+  font-size: 18px;
+  line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+.navbar-brand > img {
+  display: block;
+}
+ at media (min-width: 768px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: -15px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  padding: 9px 10px;
+  margin-top: 8px;
+  margin-right: 15px;
+  margin-bottom: 8px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+ at media (min-width: 768px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 20px;
+}
+ at media (max-width: 767px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 20px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 15px;
+    padding-bottom: 15px;
+  }
+}
+.navbar-form {
+  padding: 10px 15px;
+  margin-top: 8px;
+  margin-right: -15px;
+  margin-bottom: 8px;
+  margin-left: -15px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+ at media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control-static {
+    display: inline-block;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+ at media (max-width: 767px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+  .navbar-form .form-group:last-child {
+    margin-bottom: 0;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-form {
+    width: auto;
+    padding-top: 0;
+    padding-bottom: 0;
+    margin-right: 0;
+    margin-left: 0;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: 8px;
+  margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 14px;
+  margin-bottom: 14px;
+}
+.navbar-text {
+  margin-top: 15px;
+  margin-bottom: 15px;
+}
+ at media (min-width: 768px) {
+  .navbar-text {
+    float: left;
+    margin-right: 15px;
+    margin-left: 15px;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-left {
+    float: left !important;
+  }
+  .navbar-right {
+    float: right !important;
+    margin-right: -15px;
+  }
+  .navbar-right ~ .navbar-right {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #ccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+ at media (max-width: 767px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #555;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333;
+}
+.navbar-default .btn-link {
+  color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #ccc;
+}
+.navbar-inverse {
+  background-color: #222;
+  border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+ at media (max-width: 767px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #9d9d9d;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #fff;
+}
+.navbar-inverse .btn-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  padding: 0 5px;
+  color: #ccc;
+  content: "/\00a0";
+}
+.breadcrumb > .active {
+  color: #777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 20px 0;
+  border-radius: 4px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  margin-left: -1px;
+  line-height: 1.42857143;
+  color: #337ab7;
+  text-decoration: none;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  color: #23527c;
+  background-color: #eee;
+  border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 2;
+  color: #fff;
+  cursor: default;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+  border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 18px;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-top-left-radius: 6px;
+  border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-top-right-radius: 6px;
+  border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+.pager {
+  padding-left: 0;
+  margin: 20px 0;
+  text-align: center;
+  list-style: none;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #286090;
+}
+.label-success {
+  background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #449d44;
+}
+.label-info {
+  background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #31b0d5;
+}
+.label-warning {
+  background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #ec971f;
+}
+.label-danger {
+  background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #c9302c;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  background-color: #777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding: 30px 15px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 21px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+  border-radius: 6px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+ at media screen and (min-width: 768px) {
+  .jumbotron {
+    padding: 48px 0;
+  }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    padding-right: 60px;
+    padding-left: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 63px;
+  }
+}
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 20px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: border .2s ease-in-out;
+       -o-transition: border .2s ease-in-out;
+          transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-right: auto;
+  margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #337ab7;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #333;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.alert-success hr {
+  border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+  color: #2b542c;
+}
+.alert-info {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.alert-info hr {
+  border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+  color: #245269;
+}
+.alert-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.alert-warning hr {
+  border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+  color: #66512c;
+}
+.alert-danger {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.alert-danger hr {
+  border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+  color: #843534;
+}
+ at -webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+ at -o-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+ at keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+.progress {
+  height: 20px;
+  margin-bottom: 20px;
+  overflow: hidden;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+  float: left;
+  width: 0;
+  height: 100%;
+  font-size: 12px;
+  line-height: 20px;
+  color: #fff;
+  text-align: center;
+  background-color: #337ab7;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+  -webkit-transition: width .6s ease;
+       -o-transition: width .6s ease;
+          transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  -webkit-background-size: 40px 40px;
+          background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+       -o-animation: progress-bar-stripes 2s linear infinite;
+          animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+  background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+.media-middle {
+  vertical-align: middle;
+}
+.media-bottom {
+  vertical-align: bottom;
+}
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  padding-left: 0;
+  margin-bottom: 20px;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+a.list-group-item {
+  color: #555;
+}
+a.list-group-item .list-group-item-heading {
+  color: #333;
+}
+a.list-group-item:hover,
+a.list-group-item:focus {
+  color: #555;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #c7ddef;
+}
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+}
+a.list-group-item-success {
+  color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+a.list-group-item-success:focus {
+  color: #3c763d;
+  background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3c763d;
+  border-color: #3c763d;
+}
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7;
+}
+a.list-group-item-info {
+  color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+a.list-group-item-info:focus {
+  color: #31708f;
+  background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #31708f;
+  border-color: #31708f;
+}
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+a.list-group-item-warning {
+  color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+a.list-group-item-warning:focus {
+  color: #8a6d3b;
+  background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #8a6d3b;
+  border-color: #8a6d3b;
+}
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede;
+}
+a.list-group-item-danger {
+  color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+a.list-group-item-danger:focus {
+  color: #a94442;
+  background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #a94442;
+  border-color: #a94442;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 20px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 16px;
+  color: inherit;
+}
+.panel-title > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  margin-bottom: 0;
+  border: 0;
+}
+.panel-group {
+  margin-bottom: 20px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 4px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+  border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #ddd;
+}
+.panel-default {
+  border-color: #ddd;
+}
+.panel-default > .panel-heading {
+  color: #333;
+  background-color: #f5f5f5;
+  border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ddd;
+}
+.panel-primary {
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #337ab7;
+}
+.panel-success {
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+  color: #dff0d8;
+  background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d6e9c6;
+}
+.panel-info {
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+  color: #d9edf7;
+  background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #bce8f1;
+}
+.panel-warning {
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+  color: #fcf8e3;
+  background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #faebcc;
+}
+.panel-danger {
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f2dede;
+  background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  border: 0;
+}
+.embed-responsive.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 6px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 3px;
+}
+.close {
+  float: right;
+  font-size: 21px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  filter: alpha(opacity=20);
+  opacity: .2;
+}
+.close:hover,
+.close:focus {
+  color: #000;
+  text-decoration: none;
+  cursor: pointer;
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+button.close {
+  -webkit-appearance: none;
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  display: none;
+  overflow: hidden;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transition: -webkit-transform .3s ease-out;
+       -o-transition:      -o-transform .3s ease-out;
+          transition:         transform .3s ease-out;
+  -webkit-transform: translate(0, -25%);
+      -ms-transform: translate(0, -25%);
+       -o-transform: translate(0, -25%);
+          transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate(0, 0);
+      -ms-transform: translate(0, 0);
+       -o-transform: translate(0, 0);
+          transform: translate(0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  outline: 0;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+  position: absolute;
+  top: 0;
+  right: 0;
+  left: 0;
+  background-color: #000;
+}
+.modal-backdrop.fade {
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.modal-backdrop.in {
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.modal-header {
+  min-height: 16.42857143px;
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-bottom: 0;
+  margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+ at media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+ at media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 12px;
+  font-weight: normal;
+  line-height: 1.4;
+  visibility: visible;
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.tooltip.in {
+  filter: alpha(opacity=90);
+  opacity: .9;
+}
+.tooltip.top {
+  padding: 5px 0;
+  margin-top: -3px;
+}
+.tooltip.right {
+  padding: 0 5px;
+  margin-left: 3px;
+}
+.tooltip.bottom {
+  padding: 5px 0;
+  margin-top: 3px;
+}
+.tooltip.left {
+  padding: 0 5px;
+  margin-left: -3px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  text-decoration: none;
+  background-color: #000;
+  border-radius: 4px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  right: 5px;
+  bottom: 0;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: left;
+  white-space: normal;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  padding: 8px 14px;
+  margin: 0;
+  font-size: 14px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  content: "";
+  border-width: 10px;
+}
+.popover.top > .arrow {
+  bottom: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-color: #999;
+  border-top-color: rgba(0, 0, 0, .25);
+  border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+  bottom: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-color: #fff;
+  border-bottom-width: 0;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-right-color: #999;
+  border-right-color: rgba(0, 0, 0, .25);
+  border-left-width: 0;
+}
+.popover.right > .arrow:after {
+  bottom: -10px;
+  left: 1px;
+  content: " ";
+  border-right-color: #fff;
+  border-left-width: 0;
+}
+.popover.bottom > .arrow {
+  top: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999;
+  border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+  top: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999;
+  border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+  right: 1px;
+  bottom: -10px;
+  content: " ";
+  border-right-width: 0;
+  border-left-color: #fff;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+.carousel-inner > .item {
+  position: relative;
+  display: none;
+  -webkit-transition: .6s ease-in-out left;
+       -o-transition: .6s ease-in-out left;
+          transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+ at media all and (transform-3d), (-webkit-transform-3d) {
+  .carousel-inner > .item {
+    -webkit-transition: -webkit-transform .6s ease-in-out;
+         -o-transition:      -o-transform .6s ease-in-out;
+            transition:         transform .6s ease-in-out;
+
+    -webkit-backface-visibility: hidden;
+            backface-visibility: hidden;
+    -webkit-perspective: 1000;
+            perspective: 1000;
+  }
+  .carousel-inner > .item.next,
+  .carousel-inner > .item.active.right {
+    left: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+            transform: translate3d(100%, 0, 0);
+  }
+  .carousel-inner > .item.prev,
+  .carousel-inner > .item.active.left {
+    left: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+            transform: translate3d(-100%, 0, 0);
+  }
+  .carousel-inner > .item.next.left,
+  .carousel-inner > .item.prev.right,
+  .carousel-inner > .item.active {
+    left: 0;
+    -webkit-transform: translate3d(0, 0, 0);
+            transform: translate3d(0, 0, 0);
+  }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 15%;
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control.right {
+  right: 0;
+  left: auto;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  color: #fff;
+  text-decoration: none;
+  filter: alpha(opacity=90);
+  outline: 0;
+  opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  margin-top: -10px;
+  font-family: serif;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  padding-left: 0;
+  margin-left: -30%;
+  text-align: center;
+  list-style: none;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+  border: 1px solid #fff;
+  border-radius: 10px;
+}
+.carousel-indicators .active {
+  width: 12px;
+  height: 12px;
+  margin: 0;
+  background-color: #fff;
+}
+.carousel-caption {
+  position: absolute;
+  right: 15%;
+  bottom: 20px;
+  left: 15%;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+ at media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -15px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -15px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -15px;
+  }
+  .carousel-caption {
+    right: 20%;
+    left: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+  display: table;
+  content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-right: auto;
+  margin-left: auto;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+  visibility: hidden !important;
+}
+.affix {
+  position: fixed;
+}
+ at -ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+ at media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+ at media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+ at media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+ at media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+ at media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.css b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 0000000..c4cadf1
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.css
@@ -0,0 +1,470 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+  text-shadow: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+}
+.btn-default {
+  text-shadow: 0 1px 0 #fff;
+  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #dbdbdb;
+  border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+  background-color: #e0e0e0;
+  background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+  background-color: #e0e0e0;
+  border-color: #dbdbdb;
+}
+.btn-default:disabled,
+.btn-default[disabled] {
+  background-color: #e0e0e0;
+  background-image: none;
+}
+.btn-primary {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+  background-color: #265a88;
+  background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #265a88;
+  border-color: #245580;
+}
+.btn-primary:disabled,
+.btn-primary[disabled] {
+  background-color: #265a88;
+  background-image: none;
+}
+.btn-success {
+  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+  background-color: #419641;
+  background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+  background-color: #419641;
+  border-color: #3e8f3e;
+}
+.btn-success:disabled,
+.btn-success[disabled] {
+  background-color: #419641;
+  background-image: none;
+}
+.btn-info {
+  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+  background-color: #2aabd2;
+  background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+  background-color: #2aabd2;
+  border-color: #28a4c9;
+}
+.btn-info:disabled,
+.btn-info[disabled] {
+  background-color: #2aabd2;
+  background-image: none;
+}
+.btn-warning {
+  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+  background-color: #eb9316;
+  background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #eb9316;
+  border-color: #e38d13;
+}
+.btn-warning:disabled,
+.btn-warning[disabled] {
+  background-color: #eb9316;
+  background-image: none;
+}
+.btn-danger {
+  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+  background-color: #c12e2a;
+  background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #c12e2a;
+  border-color: #b92c28;
+}
+.btn-danger:disabled,
+.btn-danger[disabled] {
+  background-color: #c12e2a;
+  background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  background-color: #e8e8e8;
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  background-color: #2e6da4;
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+  background-repeat: repeat-x;
+}
+.navbar-default {
+  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  border-radius: 0;
+}
+ at media (max-width: 767px) {
+  .navbar .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+    background-repeat: repeat-x;
+  }
+}
+.alert {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #b2dba1;
+}
+.alert-info {
+  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #9acfea;
+}
+.alert-warning {
+  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #f5e79e;
+}
+.alert-danger {
+  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #dca7a7;
+}
+.progress {
+  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-success {
+  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-info {
+  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-warning {
+  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-danger {
+  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  text-shadow: 0 -1px 0 #286090;
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+  text-shadow: none;
+}
+.panel {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+  background-repeat: repeat-x;
+}
+.well {
+  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #dcdcdc;
+  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.min.css b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.min.css
new file mode 100644
index 0000000..4c3e7ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap-theme.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-dange [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css
new file mode 100644
index 0000000..c6f3d21
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css
@@ -0,0 +1,6332 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+html {
+  font-family: sans-serif;
+  -webkit-text-size-adjust: 100%;
+      -ms-text-size-adjust: 100%;
+}
+body {
+  margin: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+audio,
+canvas,
+progress,
+video {
+  display: inline-block;
+  vertical-align: baseline;
+}
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+[hidden],
+template {
+  display: none;
+}
+a {
+  background-color: transparent;
+}
+a:active,
+a:hover {
+  outline: 0;
+}
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+b,
+strong {
+  font-weight: bold;
+}
+dfn {
+  font-style: italic;
+}
+h1 {
+  margin: .67em 0;
+  font-size: 2em;
+}
+mark {
+  color: #000;
+  background: #ff0;
+}
+small {
+  font-size: 80%;
+}
+sub,
+sup {
+  position: relative;
+  font-size: 75%;
+  line-height: 0;
+  vertical-align: baseline;
+}
+sup {
+  top: -.5em;
+}
+sub {
+  bottom: -.25em;
+}
+img {
+  border: 0;
+}
+svg:not(:root) {
+  overflow: hidden;
+}
+figure {
+  margin: 1em 40px;
+}
+hr {
+  height: 0;
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+}
+pre {
+  overflow: auto;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+  margin: 0;
+  font: inherit;
+  color: inherit;
+}
+button {
+  overflow: visible;
+}
+button,
+select {
+  text-transform: none;
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button;
+  cursor: pointer;
+}
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+input {
+  line-height: normal;
+}
+input[type="checkbox"],
+input[type="radio"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+  padding: 0;
+}
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-box-sizing: content-box;
+     -moz-box-sizing: content-box;
+          box-sizing: content-box;
+  -webkit-appearance: textfield;
+}
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+fieldset {
+  padding: .35em .625em .75em;
+  margin: 0 2px;
+  border: 1px solid #c0c0c0;
+}
+legend {
+  padding: 0;
+  border: 0;
+}
+textarea {
+  overflow: auto;
+}
+optgroup {
+  font-weight: bold;
+}
+table {
+  border-spacing: 0;
+  border-collapse: collapse;
+}
+td,
+th {
+  padding: 0;
+}
+/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */
+ at media print {
+  *,
+  *:before,
+  *:after {
+    color: #000 !important;
+    text-shadow: none !important;
+    background: transparent !important;
+    -webkit-box-shadow: none !important;
+            box-shadow: none !important;
+  }
+  a,
+  a:visited {
+    text-decoration: underline;
+  }
+  a[href]:after {
+    content: " (" attr(href) ")";
+  }
+  abbr[title]:after {
+    content: " (" attr(title) ")";
+  }
+  a[href^="#"]:after,
+  a[href^="javascript:"]:after {
+    content: "";
+  }
+  pre,
+  blockquote {
+    border: 1px solid #999;
+
+    page-break-inside: avoid;
+  }
+  thead {
+    display: table-header-group;
+  }
+  tr,
+  img {
+    page-break-inside: avoid;
+  }
+  img {
+    max-width: 100% !important;
+  }
+  p,
+  h2,
+  h3 {
+    orphans: 3;
+    widows: 3;
+  }
+  h2,
+  h3 {
+    page-break-after: avoid;
+  }
+  select {
+    background: #fff !important;
+  }
+  .navbar {
+    display: none;
+  }
+  .btn > .caret,
+  .dropup > .btn > .caret {
+    border-top-color: #000 !important;
+  }
+  .label {
+    border: 1px solid #000;
+  }
+  .table {
+    border-collapse: collapse !important;
+  }
+  .table td,
+  .table th {
+    background-color: #fff !important;
+  }
+  .table-bordered th,
+  .table-bordered td {
+    border: 1px solid #ddd !important;
+  }
+}
+ at font-face {
+  font-family: 'Glyphicons Halflings';
+
+  src: url('../fonts/glyphicons-halflings-regular.eot');
+  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+}
+.glyphicon {
+  position: relative;
+  top: 1px;
+  display: inline-block;
+  font-family: 'Glyphicons Halflings';
+  font-style: normal;
+  font-weight: normal;
+  line-height: 1;
+
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+.glyphicon-asterisk:before {
+  content: "\2a";
+}
+.glyphicon-plus:before {
+  content: "\2b";
+}
+.glyphicon-euro:before,
+.glyphicon-eur:before {
+  content: "\20ac";
+}
+.glyphicon-minus:before {
+  content: "\2212";
+}
+.glyphicon-cloud:before {
+  content: "\2601";
+}
+.glyphicon-envelope:before {
+  content: "\2709";
+}
+.glyphicon-pencil:before {
+  content: "\270f";
+}
+.glyphicon-glass:before {
+  content: "\e001";
+}
+.glyphicon-music:before {
+  content: "\e002";
+}
+.glyphicon-search:before {
+  content: "\e003";
+}
+.glyphicon-heart:before {
+  content: "\e005";
+}
+.glyphicon-star:before {
+  content: "\e006";
+}
+.glyphicon-star-empty:before {
+  content: "\e007";
+}
+.glyphicon-user:before {
+  content: "\e008";
+}
+.glyphicon-film:before {
+  content: "\e009";
+}
+.glyphicon-th-large:before {
+  content: "\e010";
+}
+.glyphicon-th:before {
+  content: "\e011";
+}
+.glyphicon-th-list:before {
+  content: "\e012";
+}
+.glyphicon-ok:before {
+  content: "\e013";
+}
+.glyphicon-remove:before {
+  content: "\e014";
+}
+.glyphicon-zoom-in:before {
+  content: "\e015";
+}
+.glyphicon-zoom-out:before {
+  content: "\e016";
+}
+.glyphicon-off:before {
+  content: "\e017";
+}
+.glyphicon-signal:before {
+  content: "\e018";
+}
+.glyphicon-cog:before {
+  content: "\e019";
+}
+.glyphicon-trash:before {
+  content: "\e020";
+}
+.glyphicon-home:before {
+  content: "\e021";
+}
+.glyphicon-file:before {
+  content: "\e022";
+}
+.glyphicon-time:before {
+  content: "\e023";
+}
+.glyphicon-road:before {
+  content: "\e024";
+}
+.glyphicon-download-alt:before {
+  content: "\e025";
+}
+.glyphicon-download:before {
+  content: "\e026";
+}
+.glyphicon-upload:before {
+  content: "\e027";
+}
+.glyphicon-inbox:before {
+  content: "\e028";
+}
+.glyphicon-play-circle:before {
+  content: "\e029";
+}
+.glyphicon-repeat:before {
+  content: "\e030";
+}
+.glyphicon-refresh:before {
+  content: "\e031";
+}
+.glyphicon-list-alt:before {
+  content: "\e032";
+}
+.glyphicon-lock:before {
+  content: "\e033";
+}
+.glyphicon-flag:before {
+  content: "\e034";
+}
+.glyphicon-headphones:before {
+  content: "\e035";
+}
+.glyphicon-volume-off:before {
+  content: "\e036";
+}
+.glyphicon-volume-down:before {
+  content: "\e037";
+}
+.glyphicon-volume-up:before {
+  content: "\e038";
+}
+.glyphicon-qrcode:before {
+  content: "\e039";
+}
+.glyphicon-barcode:before {
+  content: "\e040";
+}
+.glyphicon-tag:before {
+  content: "\e041";
+}
+.glyphicon-tags:before {
+  content: "\e042";
+}
+.glyphicon-book:before {
+  content: "\e043";
+}
+.glyphicon-bookmark:before {
+  content: "\e044";
+}
+.glyphicon-print:before {
+  content: "\e045";
+}
+.glyphicon-camera:before {
+  content: "\e046";
+}
+.glyphicon-font:before {
+  content: "\e047";
+}
+.glyphicon-bold:before {
+  content: "\e048";
+}
+.glyphicon-italic:before {
+  content: "\e049";
+}
+.glyphicon-text-height:before {
+  content: "\e050";
+}
+.glyphicon-text-width:before {
+  content: "\e051";
+}
+.glyphicon-align-left:before {
+  content: "\e052";
+}
+.glyphicon-align-center:before {
+  content: "\e053";
+}
+.glyphicon-align-right:before {
+  content: "\e054";
+}
+.glyphicon-align-justify:before {
+  content: "\e055";
+}
+.glyphicon-list:before {
+  content: "\e056";
+}
+.glyphicon-indent-left:before {
+  content: "\e057";
+}
+.glyphicon-indent-right:before {
+  content: "\e058";
+}
+.glyphicon-facetime-video:before {
+  content: "\e059";
+}
+.glyphicon-picture:before {
+  content: "\e060";
+}
+.glyphicon-map-marker:before {
+  content: "\e062";
+}
+.glyphicon-adjust:before {
+  content: "\e063";
+}
+.glyphicon-tint:before {
+  content: "\e064";
+}
+.glyphicon-edit:before {
+  content: "\e065";
+}
+.glyphicon-share:before {
+  content: "\e066";
+}
+.glyphicon-check:before {
+  content: "\e067";
+}
+.glyphicon-move:before {
+  content: "\e068";
+}
+.glyphicon-step-backward:before {
+  content: "\e069";
+}
+.glyphicon-fast-backward:before {
+  content: "\e070";
+}
+.glyphicon-backward:before {
+  content: "\e071";
+}
+.glyphicon-play:before {
+  content: "\e072";
+}
+.glyphicon-pause:before {
+  content: "\e073";
+}
+.glyphicon-stop:before {
+  content: "\e074";
+}
+.glyphicon-forward:before {
+  content: "\e075";
+}
+.glyphicon-fast-forward:before {
+  content: "\e076";
+}
+.glyphicon-step-forward:before {
+  content: "\e077";
+}
+.glyphicon-eject:before {
+  content: "\e078";
+}
+.glyphicon-chevron-left:before {
+  content: "\e079";
+}
+.glyphicon-chevron-right:before {
+  content: "\e080";
+}
+.glyphicon-plus-sign:before {
+  content: "\e081";
+}
+.glyphicon-minus-sign:before {
+  content: "\e082";
+}
+.glyphicon-remove-sign:before {
+  content: "\e083";
+}
+.glyphicon-ok-sign:before {
+  content: "\e084";
+}
+.glyphicon-question-sign:before {
+  content: "\e085";
+}
+.glyphicon-info-sign:before {
+  content: "\e086";
+}
+.glyphicon-screenshot:before {
+  content: "\e087";
+}
+.glyphicon-remove-circle:before {
+  content: "\e088";
+}
+.glyphicon-ok-circle:before {
+  content: "\e089";
+}
+.glyphicon-ban-circle:before {
+  content: "\e090";
+}
+.glyphicon-arrow-left:before {
+  content: "\e091";
+}
+.glyphicon-arrow-right:before {
+  content: "\e092";
+}
+.glyphicon-arrow-up:before {
+  content: "\e093";
+}
+.glyphicon-arrow-down:before {
+  content: "\e094";
+}
+.glyphicon-share-alt:before {
+  content: "\e095";
+}
+.glyphicon-resize-full:before {
+  content: "\e096";
+}
+.glyphicon-resize-small:before {
+  content: "\e097";
+}
+.glyphicon-exclamation-sign:before {
+  content: "\e101";
+}
+.glyphicon-gift:before {
+  content: "\e102";
+}
+.glyphicon-leaf:before {
+  content: "\e103";
+}
+.glyphicon-fire:before {
+  content: "\e104";
+}
+.glyphicon-eye-open:before {
+  content: "\e105";
+}
+.glyphicon-eye-close:before {
+  content: "\e106";
+}
+.glyphicon-warning-sign:before {
+  content: "\e107";
+}
+.glyphicon-plane:before {
+  content: "\e108";
+}
+.glyphicon-calendar:before {
+  content: "\e109";
+}
+.glyphicon-random:before {
+  content: "\e110";
+}
+.glyphicon-comment:before {
+  content: "\e111";
+}
+.glyphicon-magnet:before {
+  content: "\e112";
+}
+.glyphicon-chevron-up:before {
+  content: "\e113";
+}
+.glyphicon-chevron-down:before {
+  content: "\e114";
+}
+.glyphicon-retweet:before {
+  content: "\e115";
+}
+.glyphicon-shopping-cart:before {
+  content: "\e116";
+}
+.glyphicon-folder-close:before {
+  content: "\e117";
+}
+.glyphicon-folder-open:before {
+  content: "\e118";
+}
+.glyphicon-resize-vertical:before {
+  content: "\e119";
+}
+.glyphicon-resize-horizontal:before {
+  content: "\e120";
+}
+.glyphicon-hdd:before {
+  content: "\e121";
+}
+.glyphicon-bullhorn:before {
+  content: "\e122";
+}
+.glyphicon-bell:before {
+  content: "\e123";
+}
+.glyphicon-certificate:before {
+  content: "\e124";
+}
+.glyphicon-thumbs-up:before {
+  content: "\e125";
+}
+.glyphicon-thumbs-down:before {
+  content: "\e126";
+}
+.glyphicon-hand-right:before {
+  content: "\e127";
+}
+.glyphicon-hand-left:before {
+  content: "\e128";
+}
+.glyphicon-hand-up:before {
+  content: "\e129";
+}
+.glyphicon-hand-down:before {
+  content: "\e130";
+}
+.glyphicon-circle-arrow-right:before {
+  content: "\e131";
+}
+.glyphicon-circle-arrow-left:before {
+  content: "\e132";
+}
+.glyphicon-circle-arrow-up:before {
+  content: "\e133";
+}
+.glyphicon-circle-arrow-down:before {
+  content: "\e134";
+}
+.glyphicon-globe:before {
+  content: "\e135";
+}
+.glyphicon-wrench:before {
+  content: "\e136";
+}
+.glyphicon-tasks:before {
+  content: "\e137";
+}
+.glyphicon-filter:before {
+  content: "\e138";
+}
+.glyphicon-briefcase:before {
+  content: "\e139";
+}
+.glyphicon-fullscreen:before {
+  content: "\e140";
+}
+.glyphicon-dashboard:before {
+  content: "\e141";
+}
+.glyphicon-paperclip:before {
+  content: "\e142";
+}
+.glyphicon-heart-empty:before {
+  content: "\e143";
+}
+.glyphicon-link:before {
+  content: "\e144";
+}
+.glyphicon-phone:before {
+  content: "\e145";
+}
+.glyphicon-pushpin:before {
+  content: "\e146";
+}
+.glyphicon-usd:before {
+  content: "\e148";
+}
+.glyphicon-gbp:before {
+  content: "\e149";
+}
+.glyphicon-sort:before {
+  content: "\e150";
+}
+.glyphicon-sort-by-alphabet:before {
+  content: "\e151";
+}
+.glyphicon-sort-by-alphabet-alt:before {
+  content: "\e152";
+}
+.glyphicon-sort-by-order:before {
+  content: "\e153";
+}
+.glyphicon-sort-by-order-alt:before {
+  content: "\e154";
+}
+.glyphicon-sort-by-attributes:before {
+  content: "\e155";
+}
+.glyphicon-sort-by-attributes-alt:before {
+  content: "\e156";
+}
+.glyphicon-unchecked:before {
+  content: "\e157";
+}
+.glyphicon-expand:before {
+  content: "\e158";
+}
+.glyphicon-collapse-down:before {
+  content: "\e159";
+}
+.glyphicon-collapse-up:before {
+  content: "\e160";
+}
+.glyphicon-log-in:before {
+  content: "\e161";
+}
+.glyphicon-flash:before {
+  content: "\e162";
+}
+.glyphicon-log-out:before {
+  content: "\e163";
+}
+.glyphicon-new-window:before {
+  content: "\e164";
+}
+.glyphicon-record:before {
+  content: "\e165";
+}
+.glyphicon-save:before {
+  content: "\e166";
+}
+.glyphicon-open:before {
+  content: "\e167";
+}
+.glyphicon-saved:before {
+  content: "\e168";
+}
+.glyphicon-import:before {
+  content: "\e169";
+}
+.glyphicon-export:before {
+  content: "\e170";
+}
+.glyphicon-send:before {
+  content: "\e171";
+}
+.glyphicon-floppy-disk:before {
+  content: "\e172";
+}
+.glyphicon-floppy-saved:before {
+  content: "\e173";
+}
+.glyphicon-floppy-remove:before {
+  content: "\e174";
+}
+.glyphicon-floppy-save:before {
+  content: "\e175";
+}
+.glyphicon-floppy-open:before {
+  content: "\e176";
+}
+.glyphicon-credit-card:before {
+  content: "\e177";
+}
+.glyphicon-transfer:before {
+  content: "\e178";
+}
+.glyphicon-cutlery:before {
+  content: "\e179";
+}
+.glyphicon-header:before {
+  content: "\e180";
+}
+.glyphicon-compressed:before {
+  content: "\e181";
+}
+.glyphicon-earphone:before {
+  content: "\e182";
+}
+.glyphicon-phone-alt:before {
+  content: "\e183";
+}
+.glyphicon-tower:before {
+  content: "\e184";
+}
+.glyphicon-stats:before {
+  content: "\e185";
+}
+.glyphicon-sd-video:before {
+  content: "\e186";
+}
+.glyphicon-hd-video:before {
+  content: "\e187";
+}
+.glyphicon-subtitles:before {
+  content: "\e188";
+}
+.glyphicon-sound-stereo:before {
+  content: "\e189";
+}
+.glyphicon-sound-dolby:before {
+  content: "\e190";
+}
+.glyphicon-sound-5-1:before {
+  content: "\e191";
+}
+.glyphicon-sound-6-1:before {
+  content: "\e192";
+}
+.glyphicon-sound-7-1:before {
+  content: "\e193";
+}
+.glyphicon-copyright-mark:before {
+  content: "\e194";
+}
+.glyphicon-registration-mark:before {
+  content: "\e195";
+}
+.glyphicon-cloud-download:before {
+  content: "\e197";
+}
+.glyphicon-cloud-upload:before {
+  content: "\e198";
+}
+.glyphicon-tree-conifer:before {
+  content: "\e199";
+}
+.glyphicon-tree-deciduous:before {
+  content: "\e200";
+}
+* {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+*:before,
+*:after {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+html {
+  font-size: 10px;
+
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+}
+body {
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #333;
+  background-color: #fff;
+}
+input,
+button,
+select,
+textarea {
+  font-family: inherit;
+  font-size: inherit;
+  line-height: inherit;
+}
+a {
+  color: #337ab7;
+  text-decoration: none;
+}
+a:hover,
+a:focus {
+  color: #23527c;
+  text-decoration: underline;
+}
+a:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+figure {
+  margin: 0;
+}
+img {
+  vertical-align: middle;
+}
+.img-responsive,
+.thumbnail > img,
+.thumbnail a > img,
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  display: block;
+  max-width: 100%;
+  height: auto;
+}
+.img-rounded {
+  border-radius: 6px;
+}
+.img-thumbnail {
+  display: inline-block;
+  max-width: 100%;
+  height: auto;
+  padding: 4px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: all .2s ease-in-out;
+       -o-transition: all .2s ease-in-out;
+          transition: all .2s ease-in-out;
+}
+.img-circle {
+  border-radius: 50%;
+}
+hr {
+  margin-top: 20px;
+  margin-bottom: 20px;
+  border: 0;
+  border-top: 1px solid #eee;
+}
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  padding: 0;
+  margin: -1px;
+  overflow: hidden;
+  clip: rect(0, 0, 0, 0);
+  border: 0;
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+  position: static;
+  width: auto;
+  height: auto;
+  margin: 0;
+  overflow: visible;
+  clip: auto;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small,
+.h1 small,
+.h2 small,
+.h3 small,
+.h4 small,
+.h5 small,
+.h6 small,
+h1 .small,
+h2 .small,
+h3 .small,
+h4 .small,
+h5 .small,
+h6 .small,
+.h1 .small,
+.h2 .small,
+.h3 .small,
+.h4 .small,
+.h5 .small,
+.h6 .small {
+  font-weight: normal;
+  line-height: 1;
+  color: #777;
+}
+h1,
+.h1,
+h2,
+.h2,
+h3,
+.h3 {
+  margin-top: 20px;
+  margin-bottom: 10px;
+}
+h1 small,
+.h1 small,
+h2 small,
+.h2 small,
+h3 small,
+.h3 small,
+h1 .small,
+.h1 .small,
+h2 .small,
+.h2 .small,
+h3 .small,
+.h3 .small {
+  font-size: 65%;
+}
+h4,
+.h4,
+h5,
+.h5,
+h6,
+.h6 {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+h4 small,
+.h4 small,
+h5 small,
+.h5 small,
+h6 small,
+.h6 small,
+h4 .small,
+.h4 .small,
+h5 .small,
+.h5 .small,
+h6 .small,
+.h6 .small {
+  font-size: 75%;
+}
+h1,
+.h1 {
+  font-size: 36px;
+}
+h2,
+.h2 {
+  font-size: 30px;
+}
+h3,
+.h3 {
+  font-size: 24px;
+}
+h4,
+.h4 {
+  font-size: 18px;
+}
+h5,
+.h5 {
+  font-size: 14px;
+}
+h6,
+.h6 {
+  font-size: 12px;
+}
+p {
+  margin: 0 0 10px;
+}
+.lead {
+  margin-bottom: 20px;
+  font-size: 16px;
+  font-weight: 300;
+  line-height: 1.4;
+}
+ at media (min-width: 768px) {
+  .lead {
+    font-size: 21px;
+  }
+}
+small,
+.small {
+  font-size: 85%;
+}
+mark,
+.mark {
+  padding: .2em;
+  background-color: #fcf8e3;
+}
+.text-left {
+  text-align: left;
+}
+.text-right {
+  text-align: right;
+}
+.text-center {
+  text-align: center;
+}
+.text-justify {
+  text-align: justify;
+}
+.text-nowrap {
+  white-space: nowrap;
+}
+.text-lowercase {
+  text-transform: lowercase;
+}
+.text-uppercase {
+  text-transform: uppercase;
+}
+.text-capitalize {
+  text-transform: capitalize;
+}
+.text-muted {
+  color: #777;
+}
+.text-primary {
+  color: #337ab7;
+}
+a.text-primary:hover {
+  color: #286090;
+}
+.text-success {
+  color: #3c763d;
+}
+a.text-success:hover {
+  color: #2b542c;
+}
+.text-info {
+  color: #31708f;
+}
+a.text-info:hover {
+  color: #245269;
+}
+.text-warning {
+  color: #8a6d3b;
+}
+a.text-warning:hover {
+  color: #66512c;
+}
+.text-danger {
+  color: #a94442;
+}
+a.text-danger:hover {
+  color: #843534;
+}
+.bg-primary {
+  color: #fff;
+  background-color: #337ab7;
+}
+a.bg-primary:hover {
+  background-color: #286090;
+}
+.bg-success {
+  background-color: #dff0d8;
+}
+a.bg-success:hover {
+  background-color: #c1e2b3;
+}
+.bg-info {
+  background-color: #d9edf7;
+}
+a.bg-info:hover {
+  background-color: #afd9ee;
+}
+.bg-warning {
+  background-color: #fcf8e3;
+}
+a.bg-warning:hover {
+  background-color: #f7ecb5;
+}
+.bg-danger {
+  background-color: #f2dede;
+}
+a.bg-danger:hover {
+  background-color: #e4b9b9;
+}
+.page-header {
+  padding-bottom: 9px;
+  margin: 40px 0 20px;
+  border-bottom: 1px solid #eee;
+}
+ul,
+ol {
+  margin-top: 0;
+  margin-bottom: 10px;
+}
+ul ul,
+ol ul,
+ul ol,
+ol ol {
+  margin-bottom: 0;
+}
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
+.list-inline {
+  padding-left: 0;
+  margin-left: -5px;
+  list-style: none;
+}
+.list-inline > li {
+  display: inline-block;
+  padding-right: 5px;
+  padding-left: 5px;
+}
+dl {
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+dt,
+dd {
+  line-height: 1.42857143;
+}
+dt {
+  font-weight: bold;
+}
+dd {
+  margin-left: 0;
+}
+ at media (min-width: 768px) {
+  .dl-horizontal dt {
+    float: left;
+    width: 160px;
+    overflow: hidden;
+    clear: left;
+    text-align: right;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  .dl-horizontal dd {
+    margin-left: 180px;
+  }
+}
+abbr[title],
+abbr[data-original-title] {
+  cursor: help;
+  border-bottom: 1px dotted #777;
+}
+.initialism {
+  font-size: 90%;
+  text-transform: uppercase;
+}
+blockquote {
+  padding: 10px 20px;
+  margin: 0 0 20px;
+  font-size: 17.5px;
+  border-left: 5px solid #eee;
+}
+blockquote p:last-child,
+blockquote ul:last-child,
+blockquote ol:last-child {
+  margin-bottom: 0;
+}
+blockquote footer,
+blockquote small,
+blockquote .small {
+  display: block;
+  font-size: 80%;
+  line-height: 1.42857143;
+  color: #777;
+}
+blockquote footer:before,
+blockquote small:before,
+blockquote .small:before {
+  content: '\2014 \00A0';
+}
+.blockquote-reverse,
+blockquote.pull-right {
+  padding-right: 15px;
+  padding-left: 0;
+  text-align: right;
+  border-right: 5px solid #eee;
+  border-left: 0;
+}
+.blockquote-reverse footer:before,
+blockquote.pull-right footer:before,
+.blockquote-reverse small:before,
+blockquote.pull-right small:before,
+.blockquote-reverse .small:before,
+blockquote.pull-right .small:before {
+  content: '';
+}
+.blockquote-reverse footer:after,
+blockquote.pull-right footer:after,
+.blockquote-reverse small:after,
+blockquote.pull-right small:after,
+.blockquote-reverse .small:after,
+blockquote.pull-right .small:after {
+  content: '\00A0 \2014';
+}
+address {
+  margin-bottom: 20px;
+  font-style: normal;
+  line-height: 1.42857143;
+}
+code,
+kbd,
+pre,
+samp {
+  font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+}
+code {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #c7254e;
+  background-color: #f9f2f4;
+  border-radius: 4px;
+}
+kbd {
+  padding: 2px 4px;
+  font-size: 90%;
+  color: #fff;
+  background-color: #333;
+  border-radius: 3px;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);
+}
+kbd kbd {
+  padding: 0;
+  font-size: 100%;
+  font-weight: bold;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+pre {
+  display: block;
+  padding: 9.5px;
+  margin: 0 0 10px;
+  font-size: 13px;
+  line-height: 1.42857143;
+  color: #333;
+  word-break: break-all;
+  word-wrap: break-word;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+pre code {
+  padding: 0;
+  font-size: inherit;
+  color: inherit;
+  white-space: pre-wrap;
+  background-color: transparent;
+  border-radius: 0;
+}
+.pre-scrollable {
+  max-height: 340px;
+  overflow-y: scroll;
+}
+.container {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+ at media (min-width: 768px) {
+  .container {
+    width: 750px;
+  }
+}
+ at media (min-width: 992px) {
+  .container {
+    width: 970px;
+  }
+}
+ at media (min-width: 1200px) {
+  .container {
+    width: 1170px;
+  }
+}
+.container-fluid {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-right: auto;
+  margin-left: auto;
+}
+.row {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11,  [...]
+  position: relative;
+  min-height: 1px;
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
+  float: left;
+}
+.col-xs-12 {
+  width: 100%;
+}
+.col-xs-11 {
+  width: 91.66666667%;
+}
+.col-xs-10 {
+  width: 83.33333333%;
+}
+.col-xs-9 {
+  width: 75%;
+}
+.col-xs-8 {
+  width: 66.66666667%;
+}
+.col-xs-7 {
+  width: 58.33333333%;
+}
+.col-xs-6 {
+  width: 50%;
+}
+.col-xs-5 {
+  width: 41.66666667%;
+}
+.col-xs-4 {
+  width: 33.33333333%;
+}
+.col-xs-3 {
+  width: 25%;
+}
+.col-xs-2 {
+  width: 16.66666667%;
+}
+.col-xs-1 {
+  width: 8.33333333%;
+}
+.col-xs-pull-12 {
+  right: 100%;
+}
+.col-xs-pull-11 {
+  right: 91.66666667%;
+}
+.col-xs-pull-10 {
+  right: 83.33333333%;
+}
+.col-xs-pull-9 {
+  right: 75%;
+}
+.col-xs-pull-8 {
+  right: 66.66666667%;
+}
+.col-xs-pull-7 {
+  right: 58.33333333%;
+}
+.col-xs-pull-6 {
+  right: 50%;
+}
+.col-xs-pull-5 {
+  right: 41.66666667%;
+}
+.col-xs-pull-4 {
+  right: 33.33333333%;
+}
+.col-xs-pull-3 {
+  right: 25%;
+}
+.col-xs-pull-2 {
+  right: 16.66666667%;
+}
+.col-xs-pull-1 {
+  right: 8.33333333%;
+}
+.col-xs-pull-0 {
+  right: auto;
+}
+.col-xs-push-12 {
+  left: 100%;
+}
+.col-xs-push-11 {
+  left: 91.66666667%;
+}
+.col-xs-push-10 {
+  left: 83.33333333%;
+}
+.col-xs-push-9 {
+  left: 75%;
+}
+.col-xs-push-8 {
+  left: 66.66666667%;
+}
+.col-xs-push-7 {
+  left: 58.33333333%;
+}
+.col-xs-push-6 {
+  left: 50%;
+}
+.col-xs-push-5 {
+  left: 41.66666667%;
+}
+.col-xs-push-4 {
+  left: 33.33333333%;
+}
+.col-xs-push-3 {
+  left: 25%;
+}
+.col-xs-push-2 {
+  left: 16.66666667%;
+}
+.col-xs-push-1 {
+  left: 8.33333333%;
+}
+.col-xs-push-0 {
+  left: auto;
+}
+.col-xs-offset-12 {
+  margin-left: 100%;
+}
+.col-xs-offset-11 {
+  margin-left: 91.66666667%;
+}
+.col-xs-offset-10 {
+  margin-left: 83.33333333%;
+}
+.col-xs-offset-9 {
+  margin-left: 75%;
+}
+.col-xs-offset-8 {
+  margin-left: 66.66666667%;
+}
+.col-xs-offset-7 {
+  margin-left: 58.33333333%;
+}
+.col-xs-offset-6 {
+  margin-left: 50%;
+}
+.col-xs-offset-5 {
+  margin-left: 41.66666667%;
+}
+.col-xs-offset-4 {
+  margin-left: 33.33333333%;
+}
+.col-xs-offset-3 {
+  margin-left: 25%;
+}
+.col-xs-offset-2 {
+  margin-left: 16.66666667%;
+}
+.col-xs-offset-1 {
+  margin-left: 8.33333333%;
+}
+.col-xs-offset-0 {
+  margin-left: 0;
+}
+ at media (min-width: 768px) {
+  .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {
+    float: left;
+  }
+  .col-sm-12 {
+    width: 100%;
+  }
+  .col-sm-11 {
+    width: 91.66666667%;
+  }
+  .col-sm-10 {
+    width: 83.33333333%;
+  }
+  .col-sm-9 {
+    width: 75%;
+  }
+  .col-sm-8 {
+    width: 66.66666667%;
+  }
+  .col-sm-7 {
+    width: 58.33333333%;
+  }
+  .col-sm-6 {
+    width: 50%;
+  }
+  .col-sm-5 {
+    width: 41.66666667%;
+  }
+  .col-sm-4 {
+    width: 33.33333333%;
+  }
+  .col-sm-3 {
+    width: 25%;
+  }
+  .col-sm-2 {
+    width: 16.66666667%;
+  }
+  .col-sm-1 {
+    width: 8.33333333%;
+  }
+  .col-sm-pull-12 {
+    right: 100%;
+  }
+  .col-sm-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-sm-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-sm-pull-9 {
+    right: 75%;
+  }
+  .col-sm-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-sm-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-sm-pull-6 {
+    right: 50%;
+  }
+  .col-sm-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-sm-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-sm-pull-3 {
+    right: 25%;
+  }
+  .col-sm-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-sm-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-sm-pull-0 {
+    right: auto;
+  }
+  .col-sm-push-12 {
+    left: 100%;
+  }
+  .col-sm-push-11 {
+    left: 91.66666667%;
+  }
+  .col-sm-push-10 {
+    left: 83.33333333%;
+  }
+  .col-sm-push-9 {
+    left: 75%;
+  }
+  .col-sm-push-8 {
+    left: 66.66666667%;
+  }
+  .col-sm-push-7 {
+    left: 58.33333333%;
+  }
+  .col-sm-push-6 {
+    left: 50%;
+  }
+  .col-sm-push-5 {
+    left: 41.66666667%;
+  }
+  .col-sm-push-4 {
+    left: 33.33333333%;
+  }
+  .col-sm-push-3 {
+    left: 25%;
+  }
+  .col-sm-push-2 {
+    left: 16.66666667%;
+  }
+  .col-sm-push-1 {
+    left: 8.33333333%;
+  }
+  .col-sm-push-0 {
+    left: auto;
+  }
+  .col-sm-offset-12 {
+    margin-left: 100%;
+  }
+  .col-sm-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-sm-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-sm-offset-9 {
+    margin-left: 75%;
+  }
+  .col-sm-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-sm-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-sm-offset-6 {
+    margin-left: 50%;
+  }
+  .col-sm-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-sm-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-sm-offset-3 {
+    margin-left: 25%;
+  }
+  .col-sm-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-sm-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-sm-offset-0 {
+    margin-left: 0;
+  }
+}
+ at media (min-width: 992px) {
+  .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {
+    float: left;
+  }
+  .col-md-12 {
+    width: 100%;
+  }
+  .col-md-11 {
+    width: 91.66666667%;
+  }
+  .col-md-10 {
+    width: 83.33333333%;
+  }
+  .col-md-9 {
+    width: 75%;
+  }
+  .col-md-8 {
+    width: 66.66666667%;
+  }
+  .col-md-7 {
+    width: 58.33333333%;
+  }
+  .col-md-6 {
+    width: 50%;
+  }
+  .col-md-5 {
+    width: 41.66666667%;
+  }
+  .col-md-4 {
+    width: 33.33333333%;
+  }
+  .col-md-3 {
+    width: 25%;
+  }
+  .col-md-2 {
+    width: 16.66666667%;
+  }
+  .col-md-1 {
+    width: 8.33333333%;
+  }
+  .col-md-pull-12 {
+    right: 100%;
+  }
+  .col-md-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-md-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-md-pull-9 {
+    right: 75%;
+  }
+  .col-md-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-md-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-md-pull-6 {
+    right: 50%;
+  }
+  .col-md-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-md-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-md-pull-3 {
+    right: 25%;
+  }
+  .col-md-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-md-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-md-pull-0 {
+    right: auto;
+  }
+  .col-md-push-12 {
+    left: 100%;
+  }
+  .col-md-push-11 {
+    left: 91.66666667%;
+  }
+  .col-md-push-10 {
+    left: 83.33333333%;
+  }
+  .col-md-push-9 {
+    left: 75%;
+  }
+  .col-md-push-8 {
+    left: 66.66666667%;
+  }
+  .col-md-push-7 {
+    left: 58.33333333%;
+  }
+  .col-md-push-6 {
+    left: 50%;
+  }
+  .col-md-push-5 {
+    left: 41.66666667%;
+  }
+  .col-md-push-4 {
+    left: 33.33333333%;
+  }
+  .col-md-push-3 {
+    left: 25%;
+  }
+  .col-md-push-2 {
+    left: 16.66666667%;
+  }
+  .col-md-push-1 {
+    left: 8.33333333%;
+  }
+  .col-md-push-0 {
+    left: auto;
+  }
+  .col-md-offset-12 {
+    margin-left: 100%;
+  }
+  .col-md-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-md-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-md-offset-9 {
+    margin-left: 75%;
+  }
+  .col-md-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-md-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-md-offset-6 {
+    margin-left: 50%;
+  }
+  .col-md-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-md-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-md-offset-3 {
+    margin-left: 25%;
+  }
+  .col-md-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-md-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-md-offset-0 {
+    margin-left: 0;
+  }
+}
+ at media (min-width: 1200px) {
+  .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {
+    float: left;
+  }
+  .col-lg-12 {
+    width: 100%;
+  }
+  .col-lg-11 {
+    width: 91.66666667%;
+  }
+  .col-lg-10 {
+    width: 83.33333333%;
+  }
+  .col-lg-9 {
+    width: 75%;
+  }
+  .col-lg-8 {
+    width: 66.66666667%;
+  }
+  .col-lg-7 {
+    width: 58.33333333%;
+  }
+  .col-lg-6 {
+    width: 50%;
+  }
+  .col-lg-5 {
+    width: 41.66666667%;
+  }
+  .col-lg-4 {
+    width: 33.33333333%;
+  }
+  .col-lg-3 {
+    width: 25%;
+  }
+  .col-lg-2 {
+    width: 16.66666667%;
+  }
+  .col-lg-1 {
+    width: 8.33333333%;
+  }
+  .col-lg-pull-12 {
+    right: 100%;
+  }
+  .col-lg-pull-11 {
+    right: 91.66666667%;
+  }
+  .col-lg-pull-10 {
+    right: 83.33333333%;
+  }
+  .col-lg-pull-9 {
+    right: 75%;
+  }
+  .col-lg-pull-8 {
+    right: 66.66666667%;
+  }
+  .col-lg-pull-7 {
+    right: 58.33333333%;
+  }
+  .col-lg-pull-6 {
+    right: 50%;
+  }
+  .col-lg-pull-5 {
+    right: 41.66666667%;
+  }
+  .col-lg-pull-4 {
+    right: 33.33333333%;
+  }
+  .col-lg-pull-3 {
+    right: 25%;
+  }
+  .col-lg-pull-2 {
+    right: 16.66666667%;
+  }
+  .col-lg-pull-1 {
+    right: 8.33333333%;
+  }
+  .col-lg-pull-0 {
+    right: auto;
+  }
+  .col-lg-push-12 {
+    left: 100%;
+  }
+  .col-lg-push-11 {
+    left: 91.66666667%;
+  }
+  .col-lg-push-10 {
+    left: 83.33333333%;
+  }
+  .col-lg-push-9 {
+    left: 75%;
+  }
+  .col-lg-push-8 {
+    left: 66.66666667%;
+  }
+  .col-lg-push-7 {
+    left: 58.33333333%;
+  }
+  .col-lg-push-6 {
+    left: 50%;
+  }
+  .col-lg-push-5 {
+    left: 41.66666667%;
+  }
+  .col-lg-push-4 {
+    left: 33.33333333%;
+  }
+  .col-lg-push-3 {
+    left: 25%;
+  }
+  .col-lg-push-2 {
+    left: 16.66666667%;
+  }
+  .col-lg-push-1 {
+    left: 8.33333333%;
+  }
+  .col-lg-push-0 {
+    left: auto;
+  }
+  .col-lg-offset-12 {
+    margin-left: 100%;
+  }
+  .col-lg-offset-11 {
+    margin-left: 91.66666667%;
+  }
+  .col-lg-offset-10 {
+    margin-left: 83.33333333%;
+  }
+  .col-lg-offset-9 {
+    margin-left: 75%;
+  }
+  .col-lg-offset-8 {
+    margin-left: 66.66666667%;
+  }
+  .col-lg-offset-7 {
+    margin-left: 58.33333333%;
+  }
+  .col-lg-offset-6 {
+    margin-left: 50%;
+  }
+  .col-lg-offset-5 {
+    margin-left: 41.66666667%;
+  }
+  .col-lg-offset-4 {
+    margin-left: 33.33333333%;
+  }
+  .col-lg-offset-3 {
+    margin-left: 25%;
+  }
+  .col-lg-offset-2 {
+    margin-left: 16.66666667%;
+  }
+  .col-lg-offset-1 {
+    margin-left: 8.33333333%;
+  }
+  .col-lg-offset-0 {
+    margin-left: 0;
+  }
+}
+table {
+  background-color: transparent;
+}
+caption {
+  padding-top: 8px;
+  padding-bottom: 8px;
+  color: #777;
+  text-align: left;
+}
+th {
+  text-align: left;
+}
+.table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px;
+}
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+  padding: 8px;
+  line-height: 1.42857143;
+  vertical-align: top;
+  border-top: 1px solid #ddd;
+}
+.table > thead > tr > th {
+  vertical-align: bottom;
+  border-bottom: 2px solid #ddd;
+}
+.table > caption + thead > tr:first-child > th,
+.table > colgroup + thead > tr:first-child > th,
+.table > thead:first-child > tr:first-child > th,
+.table > caption + thead > tr:first-child > td,
+.table > colgroup + thead > tr:first-child > td,
+.table > thead:first-child > tr:first-child > td {
+  border-top: 0;
+}
+.table > tbody + tbody {
+  border-top: 2px solid #ddd;
+}
+.table .table {
+  background-color: #fff;
+}
+.table-condensed > thead > tr > th,
+.table-condensed > tbody > tr > th,
+.table-condensed > tfoot > tr > th,
+.table-condensed > thead > tr > td,
+.table-condensed > tbody > tr > td,
+.table-condensed > tfoot > tr > td {
+  padding: 5px;
+}
+.table-bordered {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > tbody > tr > th,
+.table-bordered > tfoot > tr > th,
+.table-bordered > thead > tr > td,
+.table-bordered > tbody > tr > td,
+.table-bordered > tfoot > tr > td {
+  border: 1px solid #ddd;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+  border-bottom-width: 2px;
+}
+.table-striped > tbody > tr:nth-child(odd) {
+  background-color: #f9f9f9;
+}
+.table-hover > tbody > tr:hover {
+  background-color: #f5f5f5;
+}
+table col[class*="col-"] {
+  position: static;
+  display: table-column;
+  float: none;
+}
+table td[class*="col-"],
+table th[class*="col-"] {
+  position: static;
+  display: table-cell;
+  float: none;
+}
+.table > thead > tr > td.active,
+.table > tbody > tr > td.active,
+.table > tfoot > tr > td.active,
+.table > thead > tr > th.active,
+.table > tbody > tr > th.active,
+.table > tfoot > tr > th.active,
+.table > thead > tr.active > td,
+.table > tbody > tr.active > td,
+.table > tfoot > tr.active > td,
+.table > thead > tr.active > th,
+.table > tbody > tr.active > th,
+.table > tfoot > tr.active > th {
+  background-color: #f5f5f5;
+}
+.table-hover > tbody > tr > td.active:hover,
+.table-hover > tbody > tr > th.active:hover,
+.table-hover > tbody > tr.active:hover > td,
+.table-hover > tbody > tr:hover > .active,
+.table-hover > tbody > tr.active:hover > th {
+  background-color: #e8e8e8;
+}
+.table > thead > tr > td.success,
+.table > tbody > tr > td.success,
+.table > tfoot > tr > td.success,
+.table > thead > tr > th.success,
+.table > tbody > tr > th.success,
+.table > tfoot > tr > th.success,
+.table > thead > tr.success > td,
+.table > tbody > tr.success > td,
+.table > tfoot > tr.success > td,
+.table > thead > tr.success > th,
+.table > tbody > tr.success > th,
+.table > tfoot > tr.success > th {
+  background-color: #dff0d8;
+}
+.table-hover > tbody > tr > td.success:hover,
+.table-hover > tbody > tr > th.success:hover,
+.table-hover > tbody > tr.success:hover > td,
+.table-hover > tbody > tr:hover > .success,
+.table-hover > tbody > tr.success:hover > th {
+  background-color: #d0e9c6;
+}
+.table > thead > tr > td.info,
+.table > tbody > tr > td.info,
+.table > tfoot > tr > td.info,
+.table > thead > tr > th.info,
+.table > tbody > tr > th.info,
+.table > tfoot > tr > th.info,
+.table > thead > tr.info > td,
+.table > tbody > tr.info > td,
+.table > tfoot > tr.info > td,
+.table > thead > tr.info > th,
+.table > tbody > tr.info > th,
+.table > tfoot > tr.info > th {
+  background-color: #d9edf7;
+}
+.table-hover > tbody > tr > td.info:hover,
+.table-hover > tbody > tr > th.info:hover,
+.table-hover > tbody > tr.info:hover > td,
+.table-hover > tbody > tr:hover > .info,
+.table-hover > tbody > tr.info:hover > th {
+  background-color: #c4e3f3;
+}
+.table > thead > tr > td.warning,
+.table > tbody > tr > td.warning,
+.table > tfoot > tr > td.warning,
+.table > thead > tr > th.warning,
+.table > tbody > tr > th.warning,
+.table > tfoot > tr > th.warning,
+.table > thead > tr.warning > td,
+.table > tbody > tr.warning > td,
+.table > tfoot > tr.warning > td,
+.table > thead > tr.warning > th,
+.table > tbody > tr.warning > th,
+.table > tfoot > tr.warning > th {
+  background-color: #fcf8e3;
+}
+.table-hover > tbody > tr > td.warning:hover,
+.table-hover > tbody > tr > th.warning:hover,
+.table-hover > tbody > tr.warning:hover > td,
+.table-hover > tbody > tr:hover > .warning,
+.table-hover > tbody > tr.warning:hover > th {
+  background-color: #faf2cc;
+}
+.table > thead > tr > td.danger,
+.table > tbody > tr > td.danger,
+.table > tfoot > tr > td.danger,
+.table > thead > tr > th.danger,
+.table > tbody > tr > th.danger,
+.table > tfoot > tr > th.danger,
+.table > thead > tr.danger > td,
+.table > tbody > tr.danger > td,
+.table > tfoot > tr.danger > td,
+.table > thead > tr.danger > th,
+.table > tbody > tr.danger > th,
+.table > tfoot > tr.danger > th {
+  background-color: #f2dede;
+}
+.table-hover > tbody > tr > td.danger:hover,
+.table-hover > tbody > tr > th.danger:hover,
+.table-hover > tbody > tr.danger:hover > td,
+.table-hover > tbody > tr:hover > .danger,
+.table-hover > tbody > tr.danger:hover > th {
+  background-color: #ebcccc;
+}
+.table-responsive {
+  min-height: .01%;
+  overflow-x: auto;
+}
+ at media screen and (max-width: 767px) {
+  .table-responsive {
+    width: 100%;
+    margin-bottom: 15px;
+    overflow-y: hidden;
+    -ms-overflow-style: -ms-autohiding-scrollbar;
+    border: 1px solid #ddd;
+  }
+  .table-responsive > .table {
+    margin-bottom: 0;
+  }
+  .table-responsive > .table > thead > tr > th,
+  .table-responsive > .table > tbody > tr > th,
+  .table-responsive > .table > tfoot > tr > th,
+  .table-responsive > .table > thead > tr > td,
+  .table-responsive > .table > tbody > tr > td,
+  .table-responsive > .table > tfoot > tr > td {
+    white-space: nowrap;
+  }
+  .table-responsive > .table-bordered {
+    border: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:first-child,
+  .table-responsive > .table-bordered > tbody > tr > th:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+  .table-responsive > .table-bordered > thead > tr > td:first-child,
+  .table-responsive > .table-bordered > tbody > tr > td:first-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+    border-left: 0;
+  }
+  .table-responsive > .table-bordered > thead > tr > th:last-child,
+  .table-responsive > .table-bordered > tbody > tr > th:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+  .table-responsive > .table-bordered > thead > tr > td:last-child,
+  .table-responsive > .table-bordered > tbody > tr > td:last-child,
+  .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+    border-right: 0;
+  }
+  .table-responsive > .table-bordered > tbody > tr:last-child > th,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > th,
+  .table-responsive > .table-bordered > tbody > tr:last-child > td,
+  .table-responsive > .table-bordered > tfoot > tr:last-child > td {
+    border-bottom: 0;
+  }
+}
+fieldset {
+  min-width: 0;
+  padding: 0;
+  margin: 0;
+  border: 0;
+}
+legend {
+  display: block;
+  width: 100%;
+  padding: 0;
+  margin-bottom: 20px;
+  font-size: 21px;
+  line-height: inherit;
+  color: #333;
+  border: 0;
+  border-bottom: 1px solid #e5e5e5;
+}
+label {
+  display: inline-block;
+  max-width: 100%;
+  margin-bottom: 5px;
+  font-weight: bold;
+}
+input[type="search"] {
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+input[type="radio"],
+input[type="checkbox"] {
+  margin: 4px 0 0;
+  margin-top: 1px \9;
+  line-height: normal;
+}
+input[type="file"] {
+  display: block;
+}
+input[type="range"] {
+  display: block;
+  width: 100%;
+}
+select[multiple],
+select[size] {
+  height: auto;
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+output {
+  display: block;
+  padding-top: 7px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+}
+.form-control {
+  display: block;
+  width: 100%;
+  height: 34px;
+  padding: 6px 12px;
+  font-size: 14px;
+  line-height: 1.42857143;
+  color: #555;
+  background-color: #fff;
+  background-image: none;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+  -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
+       -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+          transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
+}
+.form-control:focus {
+  border-color: #66afe9;
+  outline: 0;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+          box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
+}
+.form-control::-moz-placeholder {
+  color: #999;
+  opacity: 1;
+}
+.form-control:-ms-input-placeholder {
+  color: #999;
+}
+.form-control::-webkit-input-placeholder {
+  color: #999;
+}
+.form-control[disabled],
+.form-control[readonly],
+fieldset[disabled] .form-control {
+  cursor: not-allowed;
+  background-color: #eee;
+  opacity: 1;
+}
+textarea.form-control {
+  height: auto;
+}
+input[type="search"] {
+  -webkit-appearance: none;
+}
+ at media screen and (-webkit-min-device-pixel-ratio: 0) {
+  input[type="date"],
+  input[type="time"],
+  input[type="datetime-local"],
+  input[type="month"] {
+    line-height: 34px;
+  }
+  input[type="date"].input-sm,
+  input[type="time"].input-sm,
+  input[type="datetime-local"].input-sm,
+  input[type="month"].input-sm {
+    line-height: 30px;
+  }
+  input[type="date"].input-lg,
+  input[type="time"].input-lg,
+  input[type="datetime-local"].input-lg,
+  input[type="month"].input-lg {
+    line-height: 46px;
+  }
+}
+.form-group {
+  margin-bottom: 15px;
+}
+.radio,
+.checkbox {
+  position: relative;
+  display: block;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.radio label,
+.checkbox label {
+  min-height: 20px;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  cursor: pointer;
+}
+.radio input[type="radio"],
+.radio-inline input[type="radio"],
+.checkbox input[type="checkbox"],
+.checkbox-inline input[type="checkbox"] {
+  position: absolute;
+  margin-top: 4px \9;
+  margin-left: -20px;
+}
+.radio + .radio,
+.checkbox + .checkbox {
+  margin-top: -5px;
+}
+.radio-inline,
+.checkbox-inline {
+  display: inline-block;
+  padding-left: 20px;
+  margin-bottom: 0;
+  font-weight: normal;
+  vertical-align: middle;
+  cursor: pointer;
+}
+.radio-inline + .radio-inline,
+.checkbox-inline + .checkbox-inline {
+  margin-top: 0;
+  margin-left: 10px;
+}
+input[type="radio"][disabled],
+input[type="checkbox"][disabled],
+input[type="radio"].disabled,
+input[type="checkbox"].disabled,
+fieldset[disabled] input[type="radio"],
+fieldset[disabled] input[type="checkbox"] {
+  cursor: not-allowed;
+}
+.radio-inline.disabled,
+.checkbox-inline.disabled,
+fieldset[disabled] .radio-inline,
+fieldset[disabled] .checkbox-inline {
+  cursor: not-allowed;
+}
+.radio.disabled label,
+.checkbox.disabled label,
+fieldset[disabled] .radio label,
+fieldset[disabled] .checkbox label {
+  cursor: not-allowed;
+}
+.form-control-static {
+  padding-top: 7px;
+  padding-bottom: 7px;
+  margin-bottom: 0;
+}
+.form-control-static.input-lg,
+.form-control-static.input-sm {
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-sm,
+.form-group-sm .form-control {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-sm,
+select.form-group-sm .form-control {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-sm,
+textarea.form-group-sm .form-control,
+select[multiple].input-sm,
+select[multiple].form-group-sm .form-control {
+  height: auto;
+}
+.input-lg,
+.form-group-lg .form-control {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-lg,
+select.form-group-lg .form-control {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-lg,
+textarea.form-group-lg .form-control,
+select[multiple].input-lg,
+select[multiple].form-group-lg .form-control {
+  height: auto;
+}
+.has-feedback {
+  position: relative;
+}
+.has-feedback .form-control {
+  padding-right: 42.5px;
+}
+.form-control-feedback {
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+  display: block;
+  width: 34px;
+  height: 34px;
+  line-height: 34px;
+  text-align: center;
+  pointer-events: none;
+}
+.input-lg + .form-control-feedback {
+  width: 46px;
+  height: 46px;
+  line-height: 46px;
+}
+.input-sm + .form-control-feedback {
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+}
+.has-success .help-block,
+.has-success .control-label,
+.has-success .radio,
+.has-success .checkbox,
+.has-success .radio-inline,
+.has-success .checkbox-inline,
+.has-success.radio label,
+.has-success.checkbox label,
+.has-success.radio-inline label,
+.has-success.checkbox-inline label {
+  color: #3c763d;
+}
+.has-success .form-control {
+  border-color: #3c763d;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-success .form-control:focus {
+  border-color: #2b542c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168;
+}
+.has-success .input-group-addon {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #3c763d;
+}
+.has-success .form-control-feedback {
+  color: #3c763d;
+}
+.has-warning .help-block,
+.has-warning .control-label,
+.has-warning .radio,
+.has-warning .checkbox,
+.has-warning .radio-inline,
+.has-warning .checkbox-inline,
+.has-warning.radio label,
+.has-warning.checkbox label,
+.has-warning.radio-inline label,
+.has-warning.checkbox-inline label {
+  color: #8a6d3b;
+}
+.has-warning .form-control {
+  border-color: #8a6d3b;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-warning .form-control:focus {
+  border-color: #66512c;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b;
+}
+.has-warning .input-group-addon {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #8a6d3b;
+}
+.has-warning .form-control-feedback {
+  color: #8a6d3b;
+}
+.has-error .help-block,
+.has-error .control-label,
+.has-error .radio,
+.has-error .checkbox,
+.has-error .radio-inline,
+.has-error .checkbox-inline,
+.has-error.radio label,
+.has-error.checkbox label,
+.has-error.radio-inline label,
+.has-error.checkbox-inline label {
+  color: #a94442;
+}
+.has-error .form-control {
+  border-color: #a94442;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
+}
+.has-error .form-control:focus {
+  border-color: #843534;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483;
+}
+.has-error .input-group-addon {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #a94442;
+}
+.has-error .form-control-feedback {
+  color: #a94442;
+}
+.has-feedback label ~ .form-control-feedback {
+  top: 25px;
+}
+.has-feedback label.sr-only ~ .form-control-feedback {
+  top: 0;
+}
+.help-block {
+  display: block;
+  margin-top: 5px;
+  margin-bottom: 10px;
+  color: #737373;
+}
+ at media (min-width: 768px) {
+  .form-inline .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .form-inline .form-control-static {
+    display: inline-block;
+  }
+  .form-inline .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .form-inline .input-group .input-group-addon,
+  .form-inline .input-group .input-group-btn,
+  .form-inline .input-group .form-control {
+    width: auto;
+  }
+  .form-inline .input-group > .form-control {
+    width: 100%;
+  }
+  .form-inline .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio,
+  .form-inline .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .form-inline .radio label,
+  .form-inline .checkbox label {
+    padding-left: 0;
+  }
+  .form-inline .radio input[type="radio"],
+  .form-inline .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .form-inline .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox,
+.form-horizontal .radio-inline,
+.form-horizontal .checkbox-inline {
+  padding-top: 7px;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+.form-horizontal .radio,
+.form-horizontal .checkbox {
+  min-height: 27px;
+}
+.form-horizontal .form-group {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+ at media (min-width: 768px) {
+  .form-horizontal .control-label {
+    padding-top: 7px;
+    margin-bottom: 0;
+    text-align: right;
+  }
+}
+.form-horizontal .has-feedback .form-control-feedback {
+  right: 15px;
+}
+ at media (min-width: 768px) {
+  .form-horizontal .form-group-lg .control-label {
+    padding-top: 14.3px;
+  }
+}
+ at media (min-width: 768px) {
+  .form-horizontal .form-group-sm .control-label {
+    padding-top: 6px;
+  }
+}
+.btn {
+  display: inline-block;
+  padding: 6px 12px;
+  margin-bottom: 0;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: middle;
+  -ms-touch-action: manipulation;
+      touch-action: manipulation;
+  cursor: pointer;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.btn:focus,
+.btn:active:focus,
+.btn.active:focus,
+.btn.focus,
+.btn:active.focus,
+.btn.active.focus {
+  outline: thin dotted;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+.btn:hover,
+.btn:focus,
+.btn.focus {
+  color: #333;
+  text-decoration: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn.disabled,
+.btn[disabled],
+fieldset[disabled] .btn {
+  pointer-events: none;
+  cursor: not-allowed;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+          box-shadow: none;
+  opacity: .65;
+}
+.btn-default {
+  color: #333;
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus,
+.btn-default.focus,
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  color: #333;
+  background-color: #e6e6e6;
+  border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+  background-image: none;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #fff;
+  border-color: #ccc;
+}
+.btn-default .badge {
+  color: #fff;
+  background-color: #333;
+}
+.btn-primary {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary:hover,
+.btn-primary:focus,
+.btn-primary.focus,
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  color: #fff;
+  background-color: #286090;
+  border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+  background-image: none;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #337ab7;
+  border-color: #2e6da4;
+}
+.btn-primary .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.btn-success {
+  color: #fff;
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success:hover,
+.btn-success:focus,
+.btn-success.focus,
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  color: #fff;
+  background-color: #449d44;
+  border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+  background-image: none;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #5cb85c;
+  border-color: #4cae4c;
+}
+.btn-success .badge {
+  color: #5cb85c;
+  background-color: #fff;
+}
+.btn-info {
+  color: #fff;
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info:hover,
+.btn-info:focus,
+.btn-info.focus,
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  color: #fff;
+  background-color: #31b0d5;
+  border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+  background-image: none;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #5bc0de;
+  border-color: #46b8da;
+}
+.btn-info .badge {
+  color: #5bc0de;
+  background-color: #fff;
+}
+.btn-warning {
+  color: #fff;
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning:hover,
+.btn-warning:focus,
+.btn-warning.focus,
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  color: #fff;
+  background-color: #ec971f;
+  border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+  background-image: none;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #f0ad4e;
+  border-color: #eea236;
+}
+.btn-warning .badge {
+  color: #f0ad4e;
+  background-color: #fff;
+}
+.btn-danger {
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger:hover,
+.btn-danger:focus,
+.btn-danger.focus,
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  color: #fff;
+  background-color: #c9302c;
+  border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+  background-image: none;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #d9534f;
+  border-color: #d43f3a;
+}
+.btn-danger .badge {
+  color: #d9534f;
+  background-color: #fff;
+}
+.btn-link {
+  font-weight: normal;
+  color: #337ab7;
+  border-radius: 0;
+}
+.btn-link,
+.btn-link:active,
+.btn-link.active,
+.btn-link[disabled],
+fieldset[disabled] .btn-link {
+  background-color: transparent;
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn-link,
+.btn-link:hover,
+.btn-link:focus,
+.btn-link:active {
+  border-color: transparent;
+}
+.btn-link:hover,
+.btn-link:focus {
+  color: #23527c;
+  text-decoration: underline;
+  background-color: transparent;
+}
+.btn-link[disabled]:hover,
+fieldset[disabled] .btn-link:hover,
+.btn-link[disabled]:focus,
+fieldset[disabled] .btn-link:focus {
+  color: #777;
+  text-decoration: none;
+}
+.btn-lg,
+.btn-group-lg > .btn {
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+.btn-sm,
+.btn-group-sm > .btn {
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-xs,
+.btn-group-xs > .btn {
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.btn-block {
+  display: block;
+  width: 100%;
+}
+.btn-block + .btn-block {
+  margin-top: 5px;
+}
+input[type="submit"].btn-block,
+input[type="reset"].btn-block,
+input[type="button"].btn-block {
+  width: 100%;
+}
+.fade {
+  opacity: 0;
+  -webkit-transition: opacity .15s linear;
+       -o-transition: opacity .15s linear;
+          transition: opacity .15s linear;
+}
+.fade.in {
+  opacity: 1;
+}
+.collapse {
+  display: none;
+  visibility: hidden;
+}
+.collapse.in {
+  display: block;
+  visibility: visible;
+}
+tr.collapse.in {
+  display: table-row;
+}
+tbody.collapse.in {
+  display: table-row-group;
+}
+.collapsing {
+  position: relative;
+  height: 0;
+  overflow: hidden;
+  -webkit-transition-timing-function: ease;
+       -o-transition-timing-function: ease;
+          transition-timing-function: ease;
+  -webkit-transition-duration: .35s;
+       -o-transition-duration: .35s;
+          transition-duration: .35s;
+  -webkit-transition-property: height, visibility;
+       -o-transition-property: height, visibility;
+          transition-property: height, visibility;
+}
+.caret {
+  display: inline-block;
+  width: 0;
+  height: 0;
+  margin-left: 2px;
+  vertical-align: middle;
+  border-top: 4px solid;
+  border-right: 4px solid transparent;
+  border-left: 4px solid transparent;
+}
+.dropdown {
+  position: relative;
+}
+.dropdown-toggle:focus {
+  outline: 0;
+}
+.dropdown-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  z-index: 1000;
+  display: none;
+  float: left;
+  min-width: 160px;
+  padding: 5px 0;
+  margin: 2px 0 0;
+  font-size: 14px;
+  text-align: left;
+  list-style: none;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .15);
+  border-radius: 4px;
+  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+          box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
+}
+.dropdown-menu.pull-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu .divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.dropdown-menu > li > a {
+  display: block;
+  padding: 3px 20px;
+  clear: both;
+  font-weight: normal;
+  line-height: 1.42857143;
+  color: #333;
+  white-space: nowrap;
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  color: #262626;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  color: #fff;
+  text-decoration: none;
+  background-color: #337ab7;
+  outline: 0;
+}
+.dropdown-menu > .disabled > a,
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  color: #777;
+}
+.dropdown-menu > .disabled > a:hover,
+.dropdown-menu > .disabled > a:focus {
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+  background-image: none;
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+}
+.open > .dropdown-menu {
+  display: block;
+}
+.open > a {
+  outline: 0;
+}
+.dropdown-menu-right {
+  right: 0;
+  left: auto;
+}
+.dropdown-menu-left {
+  right: auto;
+  left: 0;
+}
+.dropdown-header {
+  display: block;
+  padding: 3px 20px;
+  font-size: 12px;
+  line-height: 1.42857143;
+  color: #777;
+  white-space: nowrap;
+}
+.dropdown-backdrop {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 990;
+}
+.pull-right > .dropdown-menu {
+  right: 0;
+  left: auto;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+  content: "";
+  border-top: 0;
+  border-bottom: 4px solid;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+  top: auto;
+  bottom: 100%;
+  margin-bottom: 1px;
+}
+ at media (min-width: 768px) {
+  .navbar-right .dropdown-menu {
+    right: 0;
+    left: auto;
+  }
+  .navbar-right .dropdown-menu-left {
+    right: auto;
+    left: 0;
+  }
+}
+.btn-group,
+.btn-group-vertical {
+  position: relative;
+  display: inline-block;
+  vertical-align: middle;
+}
+.btn-group > .btn,
+.btn-group-vertical > .btn {
+  position: relative;
+  float: left;
+}
+.btn-group > .btn:hover,
+.btn-group-vertical > .btn:hover,
+.btn-group > .btn:focus,
+.btn-group-vertical > .btn:focus,
+.btn-group > .btn:active,
+.btn-group-vertical > .btn:active,
+.btn-group > .btn.active,
+.btn-group-vertical > .btn.active {
+  z-index: 2;
+}
+.btn-group .btn + .btn,
+.btn-group .btn + .btn-group,
+.btn-group .btn-group + .btn,
+.btn-group .btn-group + .btn-group {
+  margin-left: -1px;
+}
+.btn-toolbar {
+  margin-left: -5px;
+}
+.btn-toolbar .btn-group,
+.btn-toolbar .input-group {
+  float: left;
+}
+.btn-toolbar > .btn,
+.btn-toolbar > .btn-group,
+.btn-toolbar > .input-group {
+  margin-left: 5px;
+}
+.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
+  border-radius: 0;
+}
+.btn-group > .btn:first-child {
+  margin-left: 0;
+}
+.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn:last-child:not(:first-child),
+.btn-group > .dropdown-toggle:not(:first-child) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group > .btn-group {
+  float: left;
+}
+.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group > .btn-group:first-child > .btn:last-child,
+.btn-group > .btn-group:first-child > .dropdown-toggle {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child > .btn:first-child {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+  outline: 0;
+}
+.btn-group > .btn + .dropdown-toggle {
+  padding-right: 8px;
+  padding-left: 8px;
+}
+.btn-group > .btn-lg + .dropdown-toggle {
+  padding-right: 12px;
+  padding-left: 12px;
+}
+.btn-group.open .dropdown-toggle {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-group.open .dropdown-toggle.btn-link {
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn .caret {
+  margin-left: 0;
+}
+.btn-lg .caret {
+  border-width: 5px 5px 0;
+  border-bottom-width: 0;
+}
+.dropup .btn-lg .caret {
+  border-width: 0 5px 5px;
+}
+.btn-group-vertical > .btn,
+.btn-group-vertical > .btn-group,
+.btn-group-vertical > .btn-group > .btn {
+  display: block;
+  float: none;
+  width: 100%;
+  max-width: 100%;
+}
+.btn-group-vertical > .btn-group > .btn {
+  float: none;
+}
+.btn-group-vertical > .btn + .btn,
+.btn-group-vertical > .btn + .btn-group,
+.btn-group-vertical > .btn-group + .btn,
+.btn-group-vertical > .btn-group + .btn-group {
+  margin-top: -1px;
+  margin-left: 0;
+}
+.btn-group-vertical > .btn:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn:first-child:not(:last-child) {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn:last-child:not(:first-child) {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+  border-bottom-left-radius: 4px;
+}
+.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
+  border-radius: 0;
+}
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,
+.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.btn-group-justified {
+  display: table;
+  width: 100%;
+  table-layout: fixed;
+  border-collapse: separate;
+}
+.btn-group-justified > .btn,
+.btn-group-justified > .btn-group {
+  display: table-cell;
+  float: none;
+  width: 1%;
+}
+.btn-group-justified > .btn-group .btn {
+  width: 100%;
+}
+.btn-group-justified > .btn-group .dropdown-menu {
+  left: auto;
+}
+[data-toggle="buttons"] > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="radio"],
+[data-toggle="buttons"] > .btn input[type="checkbox"],
+[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] {
+  position: absolute;
+  clip: rect(0, 0, 0, 0);
+  pointer-events: none;
+}
+.input-group {
+  position: relative;
+  display: table;
+  border-collapse: separate;
+}
+.input-group[class*="col-"] {
+  float: none;
+  padding-right: 0;
+  padding-left: 0;
+}
+.input-group .form-control {
+  position: relative;
+  z-index: 2;
+  float: left;
+  width: 100%;
+  margin-bottom: 0;
+}
+.input-group-lg > .form-control,
+.input-group-lg > .input-group-addon,
+.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  padding: 10px 16px;
+  font-size: 18px;
+  line-height: 1.33;
+  border-radius: 6px;
+}
+select.input-group-lg > .form-control,
+select.input-group-lg > .input-group-addon,
+select.input-group-lg > .input-group-btn > .btn {
+  height: 46px;
+  line-height: 46px;
+}
+textarea.input-group-lg > .form-control,
+textarea.input-group-lg > .input-group-addon,
+textarea.input-group-lg > .input-group-btn > .btn,
+select[multiple].input-group-lg > .form-control,
+select[multiple].input-group-lg > .input-group-addon,
+select[multiple].input-group-lg > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-sm > .form-control,
+.input-group-sm > .input-group-addon,
+.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  padding: 5px 10px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+select.input-group-sm > .form-control,
+select.input-group-sm > .input-group-addon,
+select.input-group-sm > .input-group-btn > .btn {
+  height: 30px;
+  line-height: 30px;
+}
+textarea.input-group-sm > .form-control,
+textarea.input-group-sm > .input-group-addon,
+textarea.input-group-sm > .input-group-btn > .btn,
+select[multiple].input-group-sm > .form-control,
+select[multiple].input-group-sm > .input-group-addon,
+select[multiple].input-group-sm > .input-group-btn > .btn {
+  height: auto;
+}
+.input-group-addon,
+.input-group-btn,
+.input-group .form-control {
+  display: table-cell;
+}
+.input-group-addon:not(:first-child):not(:last-child),
+.input-group-btn:not(:first-child):not(:last-child),
+.input-group .form-control:not(:first-child):not(:last-child) {
+  border-radius: 0;
+}
+.input-group-addon,
+.input-group-btn {
+  width: 1%;
+  white-space: nowrap;
+  vertical-align: middle;
+}
+.input-group-addon {
+  padding: 6px 12px;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1;
+  color: #555;
+  text-align: center;
+  background-color: #eee;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+.input-group-addon.input-sm {
+  padding: 5px 10px;
+  font-size: 12px;
+  border-radius: 3px;
+}
+.input-group-addon.input-lg {
+  padding: 10px 16px;
+  font-size: 18px;
+  border-radius: 6px;
+}
+.input-group-addon input[type="radio"],
+.input-group-addon input[type="checkbox"] {
+  margin-top: 0;
+}
+.input-group .form-control:first-child,
+.input-group-addon:first-child,
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group > .btn,
+.input-group-btn:first-child > .dropdown-toggle,
+.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),
+.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
+.input-group-addon:first-child {
+  border-right: 0;
+}
+.input-group .form-control:last-child,
+.input-group-addon:last-child,
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group > .btn,
+.input-group-btn:last-child > .dropdown-toggle,
+.input-group-btn:first-child > .btn:not(:first-child),
+.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.input-group-addon:last-child {
+  border-left: 0;
+}
+.input-group-btn {
+  position: relative;
+  font-size: 0;
+  white-space: nowrap;
+}
+.input-group-btn > .btn {
+  position: relative;
+}
+.input-group-btn > .btn + .btn {
+  margin-left: -1px;
+}
+.input-group-btn > .btn:hover,
+.input-group-btn > .btn:focus,
+.input-group-btn > .btn:active {
+  z-index: 2;
+}
+.input-group-btn:first-child > .btn,
+.input-group-btn:first-child > .btn-group {
+  margin-right: -1px;
+}
+.input-group-btn:last-child > .btn,
+.input-group-btn:last-child > .btn-group {
+  margin-left: -1px;
+}
+.nav {
+  padding-left: 0;
+  margin-bottom: 0;
+  list-style: none;
+}
+.nav > li {
+  position: relative;
+  display: block;
+}
+.nav > li > a {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+}
+.nav > li > a:hover,
+.nav > li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.nav > li.disabled > a {
+  color: #777;
+}
+.nav > li.disabled > a:hover,
+.nav > li.disabled > a:focus {
+  color: #777;
+  text-decoration: none;
+  cursor: not-allowed;
+  background-color: transparent;
+}
+.nav .open > a,
+.nav .open > a:hover,
+.nav .open > a:focus {
+  background-color: #eee;
+  border-color: #337ab7;
+}
+.nav .nav-divider {
+  height: 1px;
+  margin: 9px 0;
+  overflow: hidden;
+  background-color: #e5e5e5;
+}
+.nav > li > a > img {
+  max-width: none;
+}
+.nav-tabs {
+  border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+  float: left;
+  margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+  margin-right: 2px;
+  line-height: 1.42857143;
+  border: 1px solid transparent;
+  border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+  border-color: #eee #eee #ddd;
+}
+.nav-tabs > li.active > a,
+.nav-tabs > li.active > a:hover,
+.nav-tabs > li.active > a:focus {
+  color: #555;
+  cursor: default;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-bottom-color: transparent;
+}
+.nav-tabs.nav-justified {
+  width: 100%;
+  border-bottom: 0;
+}
+.nav-tabs.nav-justified > li {
+  float: none;
+}
+.nav-tabs.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-tabs.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+ at media (min-width: 768px) {
+  .nav-tabs.nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-tabs.nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs.nav-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs.nav-justified > .active > a,
+.nav-tabs.nav-justified > .active > a:hover,
+.nav-tabs.nav-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+ at media (min-width: 768px) {
+  .nav-tabs.nav-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs.nav-justified > .active > a,
+  .nav-tabs.nav-justified > .active > a:hover,
+  .nav-tabs.nav-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.nav-pills > li {
+  float: left;
+}
+.nav-pills > li > a {
+  border-radius: 4px;
+}
+.nav-pills > li + li {
+  margin-left: 2px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+  color: #fff;
+  background-color: #337ab7;
+}
+.nav-stacked > li {
+  float: none;
+}
+.nav-stacked > li + li {
+  margin-top: 2px;
+  margin-left: 0;
+}
+.nav-justified {
+  width: 100%;
+}
+.nav-justified > li {
+  float: none;
+}
+.nav-justified > li > a {
+  margin-bottom: 5px;
+  text-align: center;
+}
+.nav-justified > .dropdown .dropdown-menu {
+  top: auto;
+  left: auto;
+}
+ at media (min-width: 768px) {
+  .nav-justified > li {
+    display: table-cell;
+    width: 1%;
+  }
+  .nav-justified > li > a {
+    margin-bottom: 0;
+  }
+}
+.nav-tabs-justified {
+  border-bottom: 0;
+}
+.nav-tabs-justified > li > a {
+  margin-right: 0;
+  border-radius: 4px;
+}
+.nav-tabs-justified > .active > a,
+.nav-tabs-justified > .active > a:hover,
+.nav-tabs-justified > .active > a:focus {
+  border: 1px solid #ddd;
+}
+ at media (min-width: 768px) {
+  .nav-tabs-justified > li > a {
+    border-bottom: 1px solid #ddd;
+    border-radius: 4px 4px 0 0;
+  }
+  .nav-tabs-justified > .active > a,
+  .nav-tabs-justified > .active > a:hover,
+  .nav-tabs-justified > .active > a:focus {
+    border-bottom-color: #fff;
+  }
+}
+.tab-content > .tab-pane {
+  display: none;
+  visibility: hidden;
+}
+.tab-content > .active {
+  display: block;
+  visibility: visible;
+}
+.nav-tabs .dropdown-menu {
+  margin-top: -1px;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar {
+  position: relative;
+  min-height: 50px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+}
+ at media (min-width: 768px) {
+  .navbar {
+    border-radius: 4px;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-header {
+    float: left;
+  }
+}
+.navbar-collapse {
+  padding-right: 15px;
+  padding-left: 15px;
+  overflow-x: visible;
+  -webkit-overflow-scrolling: touch;
+  border-top: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
+}
+.navbar-collapse.in {
+  overflow-y: auto;
+}
+ at media (min-width: 768px) {
+  .navbar-collapse {
+    width: auto;
+    border-top: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-collapse.collapse {
+    display: block !important;
+    height: auto !important;
+    padding-bottom: 0;
+    overflow: visible !important;
+    visibility: visible !important;
+  }
+  .navbar-collapse.in {
+    overflow-y: visible;
+  }
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-static-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    padding-right: 0;
+    padding-left: 0;
+  }
+}
+.navbar-fixed-top .navbar-collapse,
+.navbar-fixed-bottom .navbar-collapse {
+  max-height: 340px;
+}
+ at media (max-device-width: 480px) and (orientation: landscape) {
+  .navbar-fixed-top .navbar-collapse,
+  .navbar-fixed-bottom .navbar-collapse {
+    max-height: 200px;
+  }
+}
+.container > .navbar-header,
+.container-fluid > .navbar-header,
+.container > .navbar-collapse,
+.container-fluid > .navbar-collapse {
+  margin-right: -15px;
+  margin-left: -15px;
+}
+ at media (min-width: 768px) {
+  .container > .navbar-header,
+  .container-fluid > .navbar-header,
+  .container > .navbar-collapse,
+  .container-fluid > .navbar-collapse {
+    margin-right: 0;
+    margin-left: 0;
+  }
+}
+.navbar-static-top {
+  z-index: 1000;
+  border-width: 0 0 1px;
+}
+ at media (min-width: 768px) {
+  .navbar-static-top {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  position: fixed;
+  right: 0;
+  left: 0;
+  z-index: 1030;
+}
+ at media (min-width: 768px) {
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    border-radius: 0;
+  }
+}
+.navbar-fixed-top {
+  top: 0;
+  border-width: 0 0 1px;
+}
+.navbar-fixed-bottom {
+  bottom: 0;
+  margin-bottom: 0;
+  border-width: 1px 0 0;
+}
+.navbar-brand {
+  float: left;
+  height: 50px;
+  padding: 15px 15px;
+  font-size: 18px;
+  line-height: 20px;
+}
+.navbar-brand:hover,
+.navbar-brand:focus {
+  text-decoration: none;
+}
+.navbar-brand > img {
+  display: block;
+}
+ at media (min-width: 768px) {
+  .navbar > .container .navbar-brand,
+  .navbar > .container-fluid .navbar-brand {
+    margin-left: -15px;
+  }
+}
+.navbar-toggle {
+  position: relative;
+  float: right;
+  padding: 9px 10px;
+  margin-top: 8px;
+  margin-right: 15px;
+  margin-bottom: 8px;
+  background-color: transparent;
+  background-image: none;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.navbar-toggle:focus {
+  outline: 0;
+}
+.navbar-toggle .icon-bar {
+  display: block;
+  width: 22px;
+  height: 2px;
+  border-radius: 1px;
+}
+.navbar-toggle .icon-bar + .icon-bar {
+  margin-top: 4px;
+}
+ at media (min-width: 768px) {
+  .navbar-toggle {
+    display: none;
+  }
+}
+.navbar-nav {
+  margin: 7.5px -15px;
+}
+.navbar-nav > li > a {
+  padding-top: 10px;
+  padding-bottom: 10px;
+  line-height: 20px;
+}
+ at media (max-width: 767px) {
+  .navbar-nav .open .dropdown-menu {
+    position: static;
+    float: none;
+    width: auto;
+    margin-top: 0;
+    background-color: transparent;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+  .navbar-nav .open .dropdown-menu > li > a,
+  .navbar-nav .open .dropdown-menu .dropdown-header {
+    padding: 5px 15px 5px 25px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a {
+    line-height: 20px;
+  }
+  .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-nav .open .dropdown-menu > li > a:focus {
+    background-image: none;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-nav {
+    float: left;
+    margin: 0;
+  }
+  .navbar-nav > li {
+    float: left;
+  }
+  .navbar-nav > li > a {
+    padding-top: 15px;
+    padding-bottom: 15px;
+  }
+}
+.navbar-form {
+  padding: 10px 15px;
+  margin-top: 8px;
+  margin-right: -15px;
+  margin-bottom: 8px;
+  margin-left: -15px;
+  border-top: 1px solid transparent;
+  border-bottom: 1px solid transparent;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1);
+}
+ at media (min-width: 768px) {
+  .navbar-form .form-group {
+    display: inline-block;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control {
+    display: inline-block;
+    width: auto;
+    vertical-align: middle;
+  }
+  .navbar-form .form-control-static {
+    display: inline-block;
+  }
+  .navbar-form .input-group {
+    display: inline-table;
+    vertical-align: middle;
+  }
+  .navbar-form .input-group .input-group-addon,
+  .navbar-form .input-group .input-group-btn,
+  .navbar-form .input-group .form-control {
+    width: auto;
+  }
+  .navbar-form .input-group > .form-control {
+    width: 100%;
+  }
+  .navbar-form .control-label {
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio,
+  .navbar-form .checkbox {
+    display: inline-block;
+    margin-top: 0;
+    margin-bottom: 0;
+    vertical-align: middle;
+  }
+  .navbar-form .radio label,
+  .navbar-form .checkbox label {
+    padding-left: 0;
+  }
+  .navbar-form .radio input[type="radio"],
+  .navbar-form .checkbox input[type="checkbox"] {
+    position: relative;
+    margin-left: 0;
+  }
+  .navbar-form .has-feedback .form-control-feedback {
+    top: 0;
+  }
+}
+ at media (max-width: 767px) {
+  .navbar-form .form-group {
+    margin-bottom: 5px;
+  }
+  .navbar-form .form-group:last-child {
+    margin-bottom: 0;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-form {
+    width: auto;
+    padding-top: 0;
+    padding-bottom: 0;
+    margin-right: 0;
+    margin-left: 0;
+    border: 0;
+    -webkit-box-shadow: none;
+            box-shadow: none;
+  }
+}
+.navbar-nav > li > .dropdown-menu {
+  margin-top: 0;
+  border-top-left-radius: 0;
+  border-top-right-radius: 0;
+}
+.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+}
+.navbar-btn {
+  margin-top: 8px;
+  margin-bottom: 8px;
+}
+.navbar-btn.btn-sm {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+.navbar-btn.btn-xs {
+  margin-top: 14px;
+  margin-bottom: 14px;
+}
+.navbar-text {
+  margin-top: 15px;
+  margin-bottom: 15px;
+}
+ at media (min-width: 768px) {
+  .navbar-text {
+    float: left;
+    margin-right: 15px;
+    margin-left: 15px;
+  }
+}
+ at media (min-width: 768px) {
+  .navbar-left {
+    float: left !important;
+  }
+  .navbar-right {
+    float: right !important;
+    margin-right: -15px;
+  }
+  .navbar-right ~ .navbar-right {
+    margin-right: 0;
+  }
+}
+.navbar-default {
+  background-color: #f8f8f8;
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-brand {
+  color: #777;
+}
+.navbar-default .navbar-brand:hover,
+.navbar-default .navbar-brand:focus {
+  color: #5e5e5e;
+  background-color: transparent;
+}
+.navbar-default .navbar-text {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a {
+  color: #777;
+}
+.navbar-default .navbar-nav > li > a:hover,
+.navbar-default .navbar-nav > li > a:focus {
+  color: #333;
+  background-color: transparent;
+}
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .disabled > a,
+.navbar-default .navbar-nav > .disabled > a:hover,
+.navbar-default .navbar-nav > .disabled > a:focus {
+  color: #ccc;
+  background-color: transparent;
+}
+.navbar-default .navbar-toggle {
+  border-color: #ddd;
+}
+.navbar-default .navbar-toggle:hover,
+.navbar-default .navbar-toggle:focus {
+  background-color: #ddd;
+}
+.navbar-default .navbar-toggle .icon-bar {
+  background-color: #888;
+}
+.navbar-default .navbar-collapse,
+.navbar-default .navbar-form {
+  border-color: #e7e7e7;
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .open > a:hover,
+.navbar-default .navbar-nav > .open > a:focus {
+  color: #555;
+  background-color: #e7e7e7;
+}
+ at media (max-width: 767px) {
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a {
+    color: #777;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #333;
+    background-color: transparent;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #555;
+    background-color: #e7e7e7;
+  }
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #ccc;
+    background-color: transparent;
+  }
+}
+.navbar-default .navbar-link {
+  color: #777;
+}
+.navbar-default .navbar-link:hover {
+  color: #333;
+}
+.navbar-default .btn-link {
+  color: #777;
+}
+.navbar-default .btn-link:hover,
+.navbar-default .btn-link:focus {
+  color: #333;
+}
+.navbar-default .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-default .btn-link:hover,
+.navbar-default .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-default .btn-link:focus {
+  color: #ccc;
+}
+.navbar-inverse {
+  background-color: #222;
+  border-color: #080808;
+}
+.navbar-inverse .navbar-brand {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-brand:hover,
+.navbar-inverse .navbar-brand:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-text {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-nav > li > a:hover,
+.navbar-inverse .navbar-nav > li > a:focus {
+  color: #fff;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+.navbar-inverse .navbar-nav > .disabled > a,
+.navbar-inverse .navbar-nav > .disabled > a:hover,
+.navbar-inverse .navbar-nav > .disabled > a:focus {
+  color: #444;
+  background-color: transparent;
+}
+.navbar-inverse .navbar-toggle {
+  border-color: #333;
+}
+.navbar-inverse .navbar-toggle:hover,
+.navbar-inverse .navbar-toggle:focus {
+  background-color: #333;
+}
+.navbar-inverse .navbar-toggle .icon-bar {
+  background-color: #fff;
+}
+.navbar-inverse .navbar-collapse,
+.navbar-inverse .navbar-form {
+  border-color: #101010;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:hover,
+.navbar-inverse .navbar-nav > .open > a:focus {
+  color: #fff;
+  background-color: #080808;
+}
+ at media (max-width: 767px) {
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {
+    border-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
+    color: #9d9d9d;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {
+    color: #fff;
+    background-color: transparent;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-color: #080808;
+  }
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,
+  .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {
+    color: #444;
+    background-color: transparent;
+  }
+}
+.navbar-inverse .navbar-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .navbar-link:hover {
+  color: #fff;
+}
+.navbar-inverse .btn-link {
+  color: #9d9d9d;
+}
+.navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link:focus {
+  color: #fff;
+}
+.navbar-inverse .btn-link[disabled]:hover,
+fieldset[disabled] .navbar-inverse .btn-link:hover,
+.navbar-inverse .btn-link[disabled]:focus,
+fieldset[disabled] .navbar-inverse .btn-link:focus {
+  color: #444;
+}
+.breadcrumb {
+  padding: 8px 15px;
+  margin-bottom: 20px;
+  list-style: none;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+}
+.breadcrumb > li {
+  display: inline-block;
+}
+.breadcrumb > li + li:before {
+  padding: 0 5px;
+  color: #ccc;
+  content: "/\00a0";
+}
+.breadcrumb > .active {
+  color: #777;
+}
+.pagination {
+  display: inline-block;
+  padding-left: 0;
+  margin: 20px 0;
+  border-radius: 4px;
+}
+.pagination > li {
+  display: inline;
+}
+.pagination > li > a,
+.pagination > li > span {
+  position: relative;
+  float: left;
+  padding: 6px 12px;
+  margin-left: -1px;
+  line-height: 1.42857143;
+  color: #337ab7;
+  text-decoration: none;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.pagination > li:first-child > a,
+.pagination > li:first-child > span {
+  margin-left: 0;
+  border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+.pagination > li:last-child > a,
+.pagination > li:last-child > span {
+  border-top-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+.pagination > li > a:hover,
+.pagination > li > span:hover,
+.pagination > li > a:focus,
+.pagination > li > span:focus {
+  color: #23527c;
+  background-color: #eee;
+  border-color: #ddd;
+}
+.pagination > .active > a,
+.pagination > .active > span,
+.pagination > .active > a:hover,
+.pagination > .active > span:hover,
+.pagination > .active > a:focus,
+.pagination > .active > span:focus {
+  z-index: 2;
+  color: #fff;
+  cursor: default;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.pagination > .disabled > span,
+.pagination > .disabled > span:hover,
+.pagination > .disabled > span:focus,
+.pagination > .disabled > a,
+.pagination > .disabled > a:hover,
+.pagination > .disabled > a:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+  border-color: #ddd;
+}
+.pagination-lg > li > a,
+.pagination-lg > li > span {
+  padding: 10px 16px;
+  font-size: 18px;
+}
+.pagination-lg > li:first-child > a,
+.pagination-lg > li:first-child > span {
+  border-top-left-radius: 6px;
+  border-bottom-left-radius: 6px;
+}
+.pagination-lg > li:last-child > a,
+.pagination-lg > li:last-child > span {
+  border-top-right-radius: 6px;
+  border-bottom-right-radius: 6px;
+}
+.pagination-sm > li > a,
+.pagination-sm > li > span {
+  padding: 5px 10px;
+  font-size: 12px;
+}
+.pagination-sm > li:first-child > a,
+.pagination-sm > li:first-child > span {
+  border-top-left-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.pagination-sm > li:last-child > a,
+.pagination-sm > li:last-child > span {
+  border-top-right-radius: 3px;
+  border-bottom-right-radius: 3px;
+}
+.pager {
+  padding-left: 0;
+  margin: 20px 0;
+  text-align: center;
+  list-style: none;
+}
+.pager li {
+  display: inline;
+}
+.pager li > a,
+.pager li > span {
+  display: inline-block;
+  padding: 5px 14px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+}
+.pager li > a:hover,
+.pager li > a:focus {
+  text-decoration: none;
+  background-color: #eee;
+}
+.pager .next > a,
+.pager .next > span {
+  float: right;
+}
+.pager .previous > a,
+.pager .previous > span {
+  float: left;
+}
+.pager .disabled > a,
+.pager .disabled > a:hover,
+.pager .disabled > a:focus,
+.pager .disabled > span {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #fff;
+}
+.label {
+  display: inline;
+  padding: .2em .6em .3em;
+  font-size: 75%;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  border-radius: .25em;
+}
+a.label:hover,
+a.label:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.label:empty {
+  display: none;
+}
+.btn .label {
+  position: relative;
+  top: -1px;
+}
+.label-default {
+  background-color: #777;
+}
+.label-default[href]:hover,
+.label-default[href]:focus {
+  background-color: #5e5e5e;
+}
+.label-primary {
+  background-color: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+  background-color: #286090;
+}
+.label-success {
+  background-color: #5cb85c;
+}
+.label-success[href]:hover,
+.label-success[href]:focus {
+  background-color: #449d44;
+}
+.label-info {
+  background-color: #5bc0de;
+}
+.label-info[href]:hover,
+.label-info[href]:focus {
+  background-color: #31b0d5;
+}
+.label-warning {
+  background-color: #f0ad4e;
+}
+.label-warning[href]:hover,
+.label-warning[href]:focus {
+  background-color: #ec971f;
+}
+.label-danger {
+  background-color: #d9534f;
+}
+.label-danger[href]:hover,
+.label-danger[href]:focus {
+  background-color: #c9302c;
+}
+.badge {
+  display: inline-block;
+  min-width: 10px;
+  padding: 3px 7px;
+  font-size: 12px;
+  font-weight: bold;
+  line-height: 1;
+  color: #fff;
+  text-align: center;
+  white-space: nowrap;
+  vertical-align: baseline;
+  background-color: #777;
+  border-radius: 10px;
+}
+.badge:empty {
+  display: none;
+}
+.btn .badge {
+  position: relative;
+  top: -1px;
+}
+.btn-xs .badge {
+  top: 0;
+  padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+  color: #fff;
+  text-decoration: none;
+  cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.list-group-item > .badge {
+  float: right;
+}
+.list-group-item > .badge + .badge {
+  margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+  margin-left: 3px;
+}
+.jumbotron {
+  padding: 30px 15px;
+  margin-bottom: 30px;
+  color: inherit;
+  background-color: #eee;
+}
+.jumbotron h1,
+.jumbotron .h1 {
+  color: inherit;
+}
+.jumbotron p {
+  margin-bottom: 15px;
+  font-size: 21px;
+  font-weight: 200;
+}
+.jumbotron > hr {
+  border-top-color: #d5d5d5;
+}
+.container .jumbotron,
+.container-fluid .jumbotron {
+  border-radius: 6px;
+}
+.jumbotron .container {
+  max-width: 100%;
+}
+ at media screen and (min-width: 768px) {
+  .jumbotron {
+    padding: 48px 0;
+  }
+  .container .jumbotron,
+  .container-fluid .jumbotron {
+    padding-right: 60px;
+    padding-left: 60px;
+  }
+  .jumbotron h1,
+  .jumbotron .h1 {
+    font-size: 63px;
+  }
+}
+.thumbnail {
+  display: block;
+  padding: 4px;
+  margin-bottom: 20px;
+  line-height: 1.42857143;
+  background-color: #fff;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  -webkit-transition: border .2s ease-in-out;
+       -o-transition: border .2s ease-in-out;
+          transition: border .2s ease-in-out;
+}
+.thumbnail > img,
+.thumbnail a > img {
+  margin-right: auto;
+  margin-left: auto;
+}
+a.thumbnail:hover,
+a.thumbnail:focus,
+a.thumbnail.active {
+  border-color: #337ab7;
+}
+.thumbnail .caption {
+  padding: 9px;
+  color: #333;
+}
+.alert {
+  padding: 15px;
+  margin-bottom: 20px;
+  border: 1px solid transparent;
+  border-radius: 4px;
+}
+.alert h4 {
+  margin-top: 0;
+  color: inherit;
+}
+.alert .alert-link {
+  font-weight: bold;
+}
+.alert > p,
+.alert > ul {
+  margin-bottom: 0;
+}
+.alert > p + p {
+  margin-top: 5px;
+}
+.alert-dismissable,
+.alert-dismissible {
+  padding-right: 35px;
+}
+.alert-dismissable .close,
+.alert-dismissible .close {
+  position: relative;
+  top: -2px;
+  right: -21px;
+  color: inherit;
+}
+.alert-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.alert-success hr {
+  border-top-color: #c9e2b3;
+}
+.alert-success .alert-link {
+  color: #2b542c;
+}
+.alert-info {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.alert-info hr {
+  border-top-color: #a6e1ec;
+}
+.alert-info .alert-link {
+  color: #245269;
+}
+.alert-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.alert-warning hr {
+  border-top-color: #f7e1b5;
+}
+.alert-warning .alert-link {
+  color: #66512c;
+}
+.alert-danger {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.alert-danger hr {
+  border-top-color: #e4b9c0;
+}
+.alert-danger .alert-link {
+  color: #843534;
+}
+ at -webkit-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+ at -o-keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+ at keyframes progress-bar-stripes {
+  from {
+    background-position: 40px 0;
+  }
+  to {
+    background-position: 0 0;
+  }
+}
+.progress {
+  height: 20px;
+  margin-bottom: 20px;
+  overflow: hidden;
+  background-color: #f5f5f5;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+          box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1);
+}
+.progress-bar {
+  float: left;
+  width: 0;
+  height: 100%;
+  font-size: 12px;
+  line-height: 20px;
+  color: #fff;
+  text-align: center;
+  background-color: #337ab7;
+  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+          box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15);
+  -webkit-transition: width .6s ease;
+       -o-transition: width .6s ease;
+          transition: width .6s ease;
+}
+.progress-striped .progress-bar,
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  -webkit-background-size: 40px 40px;
+          background-size: 40px 40px;
+}
+.progress.active .progress-bar,
+.progress-bar.active {
+  -webkit-animation: progress-bar-stripes 2s linear infinite;
+       -o-animation: progress-bar-stripes 2s linear infinite;
+          animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-bar-success {
+  background-color: #5cb85c;
+}
+.progress-striped .progress-bar-success {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-info {
+  background-color: #5bc0de;
+}
+.progress-striped .progress-bar-info {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-warning {
+  background-color: #f0ad4e;
+}
+.progress-striped .progress-bar-warning {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.progress-bar-danger {
+  background-color: #d9534f;
+}
+.progress-striped .progress-bar-danger {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.media {
+  margin-top: 15px;
+}
+.media:first-child {
+  margin-top: 0;
+}
+.media-right,
+.media > .pull-right {
+  padding-left: 10px;
+}
+.media-left,
+.media > .pull-left {
+  padding-right: 10px;
+}
+.media-left,
+.media-right,
+.media-body {
+  display: table-cell;
+  vertical-align: top;
+}
+.media-middle {
+  vertical-align: middle;
+}
+.media-bottom {
+  vertical-align: bottom;
+}
+.media-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.media-list {
+  padding-left: 0;
+  list-style: none;
+}
+.list-group {
+  padding-left: 0;
+  margin-bottom: 20px;
+}
+.list-group-item {
+  position: relative;
+  display: block;
+  padding: 10px 15px;
+  margin-bottom: -1px;
+  background-color: #fff;
+  border: 1px solid #ddd;
+}
+.list-group-item:first-child {
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+.list-group-item:last-child {
+  margin-bottom: 0;
+  border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+a.list-group-item {
+  color: #555;
+}
+a.list-group-item .list-group-item-heading {
+  color: #333;
+}
+a.list-group-item:hover,
+a.list-group-item:focus {
+  color: #555;
+  text-decoration: none;
+  background-color: #f5f5f5;
+}
+.list-group-item.disabled,
+.list-group-item.disabled:hover,
+.list-group-item.disabled:focus {
+  color: #777;
+  cursor: not-allowed;
+  background-color: #eee;
+}
+.list-group-item.disabled .list-group-item-heading,
+.list-group-item.disabled:hover .list-group-item-heading,
+.list-group-item.disabled:focus .list-group-item-heading {
+  color: inherit;
+}
+.list-group-item.disabled .list-group-item-text,
+.list-group-item.disabled:hover .list-group-item-text,
+.list-group-item.disabled:focus .list-group-item-text {
+  color: #777;
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  z-index: 2;
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.list-group-item.active .list-group-item-heading,
+.list-group-item.active:hover .list-group-item-heading,
+.list-group-item.active:focus .list-group-item-heading,
+.list-group-item.active .list-group-item-heading > small,
+.list-group-item.active:hover .list-group-item-heading > small,
+.list-group-item.active:focus .list-group-item-heading > small,
+.list-group-item.active .list-group-item-heading > .small,
+.list-group-item.active:hover .list-group-item-heading > .small,
+.list-group-item.active:focus .list-group-item-heading > .small {
+  color: inherit;
+}
+.list-group-item.active .list-group-item-text,
+.list-group-item.active:hover .list-group-item-text,
+.list-group-item.active:focus .list-group-item-text {
+  color: #c7ddef;
+}
+.list-group-item-success {
+  color: #3c763d;
+  background-color: #dff0d8;
+}
+a.list-group-item-success {
+  color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-success:hover,
+a.list-group-item-success:focus {
+  color: #3c763d;
+  background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus {
+  color: #fff;
+  background-color: #3c763d;
+  border-color: #3c763d;
+}
+.list-group-item-info {
+  color: #31708f;
+  background-color: #d9edf7;
+}
+a.list-group-item-info {
+  color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-info:hover,
+a.list-group-item-info:focus {
+  color: #31708f;
+  background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus {
+  color: #fff;
+  background-color: #31708f;
+  border-color: #31708f;
+}
+.list-group-item-warning {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+}
+a.list-group-item-warning {
+  color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-warning:hover,
+a.list-group-item-warning:focus {
+  color: #8a6d3b;
+  background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus {
+  color: #fff;
+  background-color: #8a6d3b;
+  border-color: #8a6d3b;
+}
+.list-group-item-danger {
+  color: #a94442;
+  background-color: #f2dede;
+}
+a.list-group-item-danger {
+  color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading {
+  color: inherit;
+}
+a.list-group-item-danger:hover,
+a.list-group-item-danger:focus {
+  color: #a94442;
+  background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus {
+  color: #fff;
+  background-color: #a94442;
+  border-color: #a94442;
+}
+.list-group-item-heading {
+  margin-top: 0;
+  margin-bottom: 5px;
+}
+.list-group-item-text {
+  margin-bottom: 0;
+  line-height: 1.3;
+}
+.panel {
+  margin-bottom: 20px;
+  background-color: #fff;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+.panel-body {
+  padding: 15px;
+}
+.panel-heading {
+  padding: 10px 15px;
+  border-bottom: 1px solid transparent;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel-heading > .dropdown .dropdown-toggle {
+  color: inherit;
+}
+.panel-title {
+  margin-top: 0;
+  margin-bottom: 0;
+  font-size: 16px;
+  color: inherit;
+}
+.panel-title > a {
+  color: inherit;
+}
+.panel-footer {
+  padding: 10px 15px;
+  background-color: #f5f5f5;
+  border-top: 1px solid #ddd;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .list-group,
+.panel > .panel-collapse > .list-group {
+  margin-bottom: 0;
+}
+.panel > .list-group .list-group-item,
+.panel > .panel-collapse > .list-group .list-group-item {
+  border-width: 1px 0;
+  border-radius: 0;
+}
+.panel > .list-group:first-child .list-group-item:first-child,
+.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {
+  border-top: 0;
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .list-group:last-child .list-group-item:last-child,
+.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {
+  border-bottom: 0;
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel-heading + .list-group .list-group-item:first-child {
+  border-top-width: 0;
+}
+.list-group + .panel-footer {
+  border-top-width: 0;
+}
+.panel > .table,
+.panel > .table-responsive > .table,
+.panel > .panel-collapse > .table {
+  margin-bottom: 0;
+}
+.panel > .table caption,
+.panel > .table-responsive > .table caption,
+.panel > .panel-collapse > .table caption {
+  padding-right: 15px;
+  padding-left: 15px;
+}
+.panel > .table:first-child,
+.panel > .table-responsive:first-child > .table:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {
+  border-top-left-radius: 3px;
+  border-top-right-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {
+  border-top-left-radius: 3px;
+}
+.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,
+.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,
+.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,
+.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {
+  border-top-right-radius: 3px;
+}
+.panel > .table:last-child,
+.panel > .table-responsive:last-child > .table:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {
+  border-bottom-right-radius: 3px;
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {
+  border-bottom-left-radius: 3px;
+}
+.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,
+.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,
+.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,
+.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {
+  border-bottom-right-radius: 3px;
+}
+.panel > .panel-body + .table,
+.panel > .panel-body + .table-responsive,
+.panel > .table + .panel-body,
+.panel > .table-responsive + .panel-body {
+  border-top: 1px solid #ddd;
+}
+.panel > .table > tbody:first-child > tr:first-child th,
+.panel > .table > tbody:first-child > tr:first-child td {
+  border-top: 0;
+}
+.panel > .table-bordered,
+.panel > .table-responsive > .table-bordered {
+  border: 0;
+}
+.panel > .table-bordered > thead > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,
+.panel > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,
+.panel > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,
+.panel > .table-bordered > thead > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,
+.panel > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,
+.panel > .table-bordered > tfoot > tr > td:first-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {
+  border-left: 0;
+}
+.panel > .table-bordered > thead > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,
+.panel > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,
+.panel > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,
+.panel > .table-bordered > thead > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,
+.panel > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,
+.panel > .table-bordered > tfoot > tr > td:last-child,
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {
+  border-right: 0;
+}
+.panel > .table-bordered > thead > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,
+.panel > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,
+.panel > .table-bordered > thead > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,
+.panel > .table-bordered > tbody > tr:first-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {
+  border-bottom: 0;
+}
+.panel > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,
+.panel > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,
+.panel > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,
+.panel > .table-bordered > tfoot > tr:last-child > th,
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {
+  border-bottom: 0;
+}
+.panel > .table-responsive {
+  margin-bottom: 0;
+  border: 0;
+}
+.panel-group {
+  margin-bottom: 20px;
+}
+.panel-group .panel {
+  margin-bottom: 0;
+  border-radius: 4px;
+}
+.panel-group .panel + .panel {
+  margin-top: 5px;
+}
+.panel-group .panel-heading {
+  border-bottom: 0;
+}
+.panel-group .panel-heading + .panel-collapse > .panel-body,
+.panel-group .panel-heading + .panel-collapse > .list-group {
+  border-top: 1px solid #ddd;
+}
+.panel-group .panel-footer {
+  border-top: 0;
+}
+.panel-group .panel-footer + .panel-collapse .panel-body {
+  border-bottom: 1px solid #ddd;
+}
+.panel-default {
+  border-color: #ddd;
+}
+.panel-default > .panel-heading {
+  color: #333;
+  background-color: #f5f5f5;
+  border-color: #ddd;
+}
+.panel-default > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ddd;
+}
+.panel-default > .panel-heading .badge {
+  color: #f5f5f5;
+  background-color: #333;
+}
+.panel-default > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ddd;
+}
+.panel-primary {
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading {
+  color: #fff;
+  background-color: #337ab7;
+  border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+  color: #337ab7;
+  background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #337ab7;
+}
+.panel-success {
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading {
+  color: #3c763d;
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+}
+.panel-success > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #d6e9c6;
+}
+.panel-success > .panel-heading .badge {
+  color: #dff0d8;
+  background-color: #3c763d;
+}
+.panel-success > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #d6e9c6;
+}
+.panel-info {
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #bce8f1;
+}
+.panel-info > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #bce8f1;
+}
+.panel-info > .panel-heading .badge {
+  color: #d9edf7;
+  background-color: #31708f;
+}
+.panel-info > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #bce8f1;
+}
+.panel-warning {
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading {
+  color: #8a6d3b;
+  background-color: #fcf8e3;
+  border-color: #faebcc;
+}
+.panel-warning > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #faebcc;
+}
+.panel-warning > .panel-heading .badge {
+  color: #fcf8e3;
+  background-color: #8a6d3b;
+}
+.panel-warning > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #faebcc;
+}
+.panel-danger {
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading {
+  color: #a94442;
+  background-color: #f2dede;
+  border-color: #ebccd1;
+}
+.panel-danger > .panel-heading + .panel-collapse > .panel-body {
+  border-top-color: #ebccd1;
+}
+.panel-danger > .panel-heading .badge {
+  color: #f2dede;
+  background-color: #a94442;
+}
+.panel-danger > .panel-footer + .panel-collapse > .panel-body {
+  border-bottom-color: #ebccd1;
+}
+.embed-responsive {
+  position: relative;
+  display: block;
+  height: 0;
+  padding: 0;
+  overflow: hidden;
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive iframe,
+.embed-responsive embed,
+.embed-responsive object,
+.embed-responsive video {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  border: 0;
+}
+.embed-responsive.embed-responsive-16by9 {
+  padding-bottom: 56.25%;
+}
+.embed-responsive.embed-responsive-4by3 {
+  padding-bottom: 75%;
+}
+.well {
+  min-height: 20px;
+  padding: 19px;
+  margin-bottom: 20px;
+  background-color: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05);
+}
+.well blockquote {
+  border-color: #ddd;
+  border-color: rgba(0, 0, 0, .15);
+}
+.well-lg {
+  padding: 24px;
+  border-radius: 6px;
+}
+.well-sm {
+  padding: 9px;
+  border-radius: 3px;
+}
+.close {
+  float: right;
+  font-size: 21px;
+  font-weight: bold;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  filter: alpha(opacity=20);
+  opacity: .2;
+}
+.close:hover,
+.close:focus {
+  color: #000;
+  text-decoration: none;
+  cursor: pointer;
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+button.close {
+  -webkit-appearance: none;
+  padding: 0;
+  cursor: pointer;
+  background: transparent;
+  border: 0;
+}
+.modal-open {
+  overflow: hidden;
+}
+.modal {
+  position: fixed;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  z-index: 1040;
+  display: none;
+  overflow: hidden;
+  -webkit-overflow-scrolling: touch;
+  outline: 0;
+}
+.modal.fade .modal-dialog {
+  -webkit-transition: -webkit-transform .3s ease-out;
+       -o-transition:      -o-transform .3s ease-out;
+          transition:         transform .3s ease-out;
+  -webkit-transform: translate(0, -25%);
+      -ms-transform: translate(0, -25%);
+       -o-transform: translate(0, -25%);
+          transform: translate(0, -25%);
+}
+.modal.in .modal-dialog {
+  -webkit-transform: translate(0, 0);
+      -ms-transform: translate(0, 0);
+       -o-transform: translate(0, 0);
+          transform: translate(0, 0);
+}
+.modal-open .modal {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+.modal-dialog {
+  position: relative;
+  width: auto;
+  margin: 10px;
+}
+.modal-content {
+  position: relative;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #999;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  outline: 0;
+  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+          box-shadow: 0 3px 9px rgba(0, 0, 0, .5);
+}
+.modal-backdrop {
+  position: absolute;
+  top: 0;
+  right: 0;
+  left: 0;
+  background-color: #000;
+}
+.modal-backdrop.fade {
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.modal-backdrop.in {
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.modal-header {
+  min-height: 16.42857143px;
+  padding: 15px;
+  border-bottom: 1px solid #e5e5e5;
+}
+.modal-header .close {
+  margin-top: -2px;
+}
+.modal-title {
+  margin: 0;
+  line-height: 1.42857143;
+}
+.modal-body {
+  position: relative;
+  padding: 15px;
+}
+.modal-footer {
+  padding: 15px;
+  text-align: right;
+  border-top: 1px solid #e5e5e5;
+}
+.modal-footer .btn + .btn {
+  margin-bottom: 0;
+  margin-left: 5px;
+}
+.modal-footer .btn-group .btn + .btn {
+  margin-left: -1px;
+}
+.modal-footer .btn-block + .btn-block {
+  margin-left: 0;
+}
+.modal-scrollbar-measure {
+  position: absolute;
+  top: -9999px;
+  width: 50px;
+  height: 50px;
+  overflow: scroll;
+}
+ at media (min-width: 768px) {
+  .modal-dialog {
+    width: 600px;
+    margin: 30px auto;
+  }
+  .modal-content {
+    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+            box-shadow: 0 5px 15px rgba(0, 0, 0, .5);
+  }
+  .modal-sm {
+    width: 300px;
+  }
+}
+ at media (min-width: 992px) {
+  .modal-lg {
+    width: 900px;
+  }
+}
+.tooltip {
+  position: absolute;
+  z-index: 1070;
+  display: block;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 12px;
+  font-weight: normal;
+  line-height: 1.4;
+  visibility: visible;
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.tooltip.in {
+  filter: alpha(opacity=90);
+  opacity: .9;
+}
+.tooltip.top {
+  padding: 5px 0;
+  margin-top: -3px;
+}
+.tooltip.right {
+  padding: 0 5px;
+  margin-left: 3px;
+}
+.tooltip.bottom {
+  padding: 5px 0;
+  margin-top: 3px;
+}
+.tooltip.left {
+  padding: 0 5px;
+  margin-left: -3px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  text-decoration: none;
+  background-color: #000;
+  border-radius: 4px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  right: 5px;
+  bottom: 0;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  margin-bottom: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  margin-top: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1060;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 1.42857143;
+  text-align: left;
+  white-space: normal;
+  background-color: #fff;
+  -webkit-background-clip: padding-box;
+          background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  padding: 8px 14px;
+  margin: 0;
+  font-size: 14px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover > .arrow,
+.popover > .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover > .arrow {
+  border-width: 11px;
+}
+.popover > .arrow:after {
+  content: "";
+  border-width: 10px;
+}
+.popover.top > .arrow {
+  bottom: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-color: #999;
+  border-top-color: rgba(0, 0, 0, .25);
+  border-bottom-width: 0;
+}
+.popover.top > .arrow:after {
+  bottom: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-color: #fff;
+  border-bottom-width: 0;
+}
+.popover.right > .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-right-color: #999;
+  border-right-color: rgba(0, 0, 0, .25);
+  border-left-width: 0;
+}
+.popover.right > .arrow:after {
+  bottom: -10px;
+  left: 1px;
+  content: " ";
+  border-right-color: #fff;
+  border-left-width: 0;
+}
+.popover.bottom > .arrow {
+  top: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999;
+  border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom > .arrow:after {
+  top: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left > .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999;
+  border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left > .arrow:after {
+  right: 1px;
+  bottom: -10px;
+  content: " ";
+  border-right-width: 0;
+  border-left-color: #fff;
+}
+.carousel {
+  position: relative;
+}
+.carousel-inner {
+  position: relative;
+  width: 100%;
+  overflow: hidden;
+}
+.carousel-inner > .item {
+  position: relative;
+  display: none;
+  -webkit-transition: .6s ease-in-out left;
+       -o-transition: .6s ease-in-out left;
+          transition: .6s ease-in-out left;
+}
+.carousel-inner > .item > img,
+.carousel-inner > .item > a > img {
+  line-height: 1;
+}
+ at media all and (transform-3d), (-webkit-transform-3d) {
+  .carousel-inner > .item {
+    -webkit-transition: -webkit-transform .6s ease-in-out;
+         -o-transition:      -o-transform .6s ease-in-out;
+            transition:         transform .6s ease-in-out;
+
+    -webkit-backface-visibility: hidden;
+            backface-visibility: hidden;
+    -webkit-perspective: 1000;
+            perspective: 1000;
+  }
+  .carousel-inner > .item.next,
+  .carousel-inner > .item.active.right {
+    left: 0;
+    -webkit-transform: translate3d(100%, 0, 0);
+            transform: translate3d(100%, 0, 0);
+  }
+  .carousel-inner > .item.prev,
+  .carousel-inner > .item.active.left {
+    left: 0;
+    -webkit-transform: translate3d(-100%, 0, 0);
+            transform: translate3d(-100%, 0, 0);
+  }
+  .carousel-inner > .item.next.left,
+  .carousel-inner > .item.prev.right,
+  .carousel-inner > .item.active {
+    left: 0;
+    -webkit-transform: translate3d(0, 0, 0);
+            transform: translate3d(0, 0, 0);
+  }
+}
+.carousel-inner > .active,
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  display: block;
+}
+.carousel-inner > .active {
+  left: 0;
+}
+.carousel-inner > .next,
+.carousel-inner > .prev {
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.carousel-inner > .next {
+  left: 100%;
+}
+.carousel-inner > .prev {
+  left: -100%;
+}
+.carousel-inner > .next.left,
+.carousel-inner > .prev.right {
+  left: 0;
+}
+.carousel-inner > .active.left {
+  left: -100%;
+}
+.carousel-inner > .active.right {
+  left: 100%;
+}
+.carousel-control {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  width: 15%;
+  font-size: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+  filter: alpha(opacity=50);
+  opacity: .5;
+}
+.carousel-control.left {
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control.right {
+  right: 0;
+  left: auto;
+  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image:      -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5)));
+  background-image:         linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
+  background-repeat: repeat-x;
+}
+.carousel-control:hover,
+.carousel-control:focus {
+  color: #fff;
+  text-decoration: none;
+  filter: alpha(opacity=90);
+  outline: 0;
+  opacity: .9;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-left,
+.carousel-control .glyphicon-chevron-right {
+  position: absolute;
+  top: 50%;
+  z-index: 5;
+  display: inline-block;
+}
+.carousel-control .icon-prev,
+.carousel-control .glyphicon-chevron-left {
+  left: 50%;
+  margin-left: -10px;
+}
+.carousel-control .icon-next,
+.carousel-control .glyphicon-chevron-right {
+  right: 50%;
+  margin-right: -10px;
+}
+.carousel-control .icon-prev,
+.carousel-control .icon-next {
+  width: 20px;
+  height: 20px;
+  margin-top: -10px;
+  font-family: serif;
+}
+.carousel-control .icon-prev:before {
+  content: '\2039';
+}
+.carousel-control .icon-next:before {
+  content: '\203a';
+}
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 50%;
+  z-index: 15;
+  width: 60%;
+  padding-left: 0;
+  margin-left: -30%;
+  text-align: center;
+  list-style: none;
+}
+.carousel-indicators li {
+  display: inline-block;
+  width: 10px;
+  height: 10px;
+  margin: 1px;
+  text-indent: -999px;
+  cursor: pointer;
+  background-color: #000 \9;
+  background-color: rgba(0, 0, 0, 0);
+  border: 1px solid #fff;
+  border-radius: 10px;
+}
+.carousel-indicators .active {
+  width: 12px;
+  height: 12px;
+  margin: 0;
+  background-color: #fff;
+}
+.carousel-caption {
+  position: absolute;
+  right: 15%;
+  bottom: 20px;
+  left: 15%;
+  z-index: 10;
+  padding-top: 20px;
+  padding-bottom: 20px;
+  color: #fff;
+  text-align: center;
+  text-shadow: 0 1px 2px rgba(0, 0, 0, .6);
+}
+.carousel-caption .btn {
+  text-shadow: none;
+}
+ at media screen and (min-width: 768px) {
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-prev,
+  .carousel-control .icon-next {
+    width: 30px;
+    height: 30px;
+    margin-top: -15px;
+    font-size: 30px;
+  }
+  .carousel-control .glyphicon-chevron-left,
+  .carousel-control .icon-prev {
+    margin-left: -15px;
+  }
+  .carousel-control .glyphicon-chevron-right,
+  .carousel-control .icon-next {
+    margin-right: -15px;
+  }
+  .carousel-caption {
+    right: 20%;
+    left: 20%;
+    padding-bottom: 30px;
+  }
+  .carousel-indicators {
+    bottom: 20px;
+  }
+}
+.clearfix:before,
+.clearfix:after,
+.dl-horizontal dd:before,
+.dl-horizontal dd:after,
+.container:before,
+.container:after,
+.container-fluid:before,
+.container-fluid:after,
+.row:before,
+.row:after,
+.form-horizontal .form-group:before,
+.form-horizontal .form-group:after,
+.btn-toolbar:before,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:before,
+.btn-group-vertical > .btn-group:after,
+.nav:before,
+.nav:after,
+.navbar:before,
+.navbar:after,
+.navbar-header:before,
+.navbar-header:after,
+.navbar-collapse:before,
+.navbar-collapse:after,
+.pager:before,
+.pager:after,
+.panel-body:before,
+.panel-body:after,
+.modal-footer:before,
+.modal-footer:after {
+  display: table;
+  content: " ";
+}
+.clearfix:after,
+.dl-horizontal dd:after,
+.container:after,
+.container-fluid:after,
+.row:after,
+.form-horizontal .form-group:after,
+.btn-toolbar:after,
+.btn-group-vertical > .btn-group:after,
+.nav:after,
+.navbar:after,
+.navbar-header:after,
+.navbar-collapse:after,
+.pager:after,
+.panel-body:after,
+.modal-footer:after {
+  clear: both;
+}
+.center-block {
+  display: block;
+  margin-right: auto;
+  margin-left: auto;
+}
+.pull-right {
+  float: right !important;
+}
+.pull-left {
+  float: left !important;
+}
+.hide {
+  display: none !important;
+}
+.show {
+  display: block !important;
+}
+.invisible {
+  visibility: hidden;
+}
+.text-hide {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+.hidden {
+  display: none !important;
+  visibility: hidden !important;
+}
+.affix {
+  position: fixed;
+}
+ at -ms-viewport {
+  width: device-width;
+}
+.visible-xs,
+.visible-sm,
+.visible-md,
+.visible-lg {
+  display: none !important;
+}
+.visible-xs-block,
+.visible-xs-inline,
+.visible-xs-inline-block,
+.visible-sm-block,
+.visible-sm-inline,
+.visible-sm-inline-block,
+.visible-md-block,
+.visible-md-inline,
+.visible-md-inline-block,
+.visible-lg-block,
+.visible-lg-inline,
+.visible-lg-inline-block {
+  display: none !important;
+}
+ at media (max-width: 767px) {
+  .visible-xs {
+    display: block !important;
+  }
+  table.visible-xs {
+    display: table;
+  }
+  tr.visible-xs {
+    display: table-row !important;
+  }
+  th.visible-xs,
+  td.visible-xs {
+    display: table-cell !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-block {
+    display: block !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-inline {
+    display: inline !important;
+  }
+}
+ at media (max-width: 767px) {
+  .visible-xs-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm {
+    display: block !important;
+  }
+  table.visible-sm {
+    display: table;
+  }
+  tr.visible-sm {
+    display: table-row !important;
+  }
+  th.visible-sm,
+  td.visible-sm {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .visible-sm-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md {
+    display: block !important;
+  }
+  table.visible-md {
+    display: table;
+  }
+  tr.visible-md {
+    display: table-row !important;
+  }
+  th.visible-md,
+  td.visible-md {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .visible-md-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg {
+    display: block !important;
+  }
+  table.visible-lg {
+    display: table;
+  }
+  tr.visible-lg {
+    display: table-row !important;
+  }
+  th.visible-lg,
+  td.visible-lg {
+    display: table-cell !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-block {
+    display: block !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-inline {
+    display: inline !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .visible-lg-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media (max-width: 767px) {
+  .hidden-xs {
+    display: none !important;
+  }
+}
+ at media (min-width: 768px) and (max-width: 991px) {
+  .hidden-sm {
+    display: none !important;
+  }
+}
+ at media (min-width: 992px) and (max-width: 1199px) {
+  .hidden-md {
+    display: none !important;
+  }
+}
+ at media (min-width: 1200px) {
+  .hidden-lg {
+    display: none !important;
+  }
+}
+.visible-print {
+  display: none !important;
+}
+ at media print {
+  .visible-print {
+    display: block !important;
+  }
+  table.visible-print {
+    display: table;
+  }
+  tr.visible-print {
+    display: table-row !important;
+  }
+  th.visible-print,
+  td.visible-print {
+    display: table-cell !important;
+  }
+}
+.visible-print-block {
+  display: none !important;
+}
+ at media print {
+  .visible-print-block {
+    display: block !important;
+  }
+}
+.visible-print-inline {
+  display: none !important;
+}
+ at media print {
+  .visible-print-inline {
+    display: inline !important;
+  }
+}
+.visible-print-inline-block {
+  display: none !important;
+}
+ at media print {
+  .visible-print-inline-block {
+    display: inline-block !important;
+  }
+}
+ at media print {
+  .hidden-print {
+    display: none !important;
+  }
+}
+/*# sourceMappingURL=bootstrap.css.map */
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css.map b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css.map
new file mode 100644
index 0000000..a02f6ba
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.les [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.min.css b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.min.css
new file mode 100644
index 0000000..b6fe4e0
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/css/bootstrap.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-b [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.eot b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 0000000..4a4ca86
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.eot differ
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.svg b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 0000000..25691af
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5 [...]
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t1 [...]
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t1 [...]
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6 [...]
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h [...]
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-3 [...]
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35. [...]
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q [...]
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 - [...]
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14. [...]
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t3 [...]
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14. [...]
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74. [...]
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28 [...]
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60  [...]
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t [...]
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -1 [...]
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100z [...]
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 - [...]
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800  [...]
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14  [...]
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 [...]
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49 [...]
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 1 [...]
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t1 [...]
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t- [...]
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg>
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.ttf b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 0000000..67fa00b
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.ttf differ
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.woff b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 0000000..8c54182
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/bootstrap/fonts/glyphicons-halflings-regular.woff differ
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.js b/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.js
new file mode 100644
index 0000000..b6ac8d9
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.js
@@ -0,0 +1,2320 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+if (typeof jQuery === 'undefined') {
+  throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+  var version = $.fn.jquery.split(' ')[0].split('.')
+  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {
+    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher')
+  }
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.3.1
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+  // ============================================================
+
+  function transitionEnd() {
+    var el = document.createElement('bootstrap')
+
+    var transEndEventNames = {
+      WebkitTransition : 'webkitTransitionEnd',
+      MozTransition    : 'transitionend',
+      OTransition      : 'oTransitionEnd otransitionend',
+      transition       : 'transitionend'
+    }
+
+    for (var name in transEndEventNames) {
+      if (el.style[name] !== undefined) {
+        return { end: transEndEventNames[name] }
+      }
+    }
+
+    return false // explicit for ie8 (  ._.)
+  }
+
+  // http://blog.alexmaccaw.com/css-transitions
+  $.fn.emulateTransitionEnd = function (duration) {
+    var called = false
+    var $el = this
+    $(this).one('bsTransitionEnd', function () { called = true })
+    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+    setTimeout(callback, duration)
+    return this
+  }
+
+  $(function () {
+    $.support.transition = transitionEnd()
+
+    if (!$.support.transition) return
+
+    $.event.special.bsTransitionEnd = {
+      bindType: $.support.transition.end,
+      delegateType: $.support.transition.end,
+      handle: function (e) {
+        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
+      }
+    }
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.3.1
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // ALERT CLASS DEFINITION
+  // ======================
+
+  var dismiss = '[data-dismiss="alert"]'
+  var Alert   = function (el) {
+    $(el).on('click', dismiss, this.close)
+  }
+
+  Alert.VERSION = '3.3.1'
+
+  Alert.TRANSITION_DURATION = 150
+
+  Alert.prototype.close = function (e) {
+    var $this    = $(this)
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    var $parent = $(selector)
+
+    if (e) e.preventDefault()
+
+    if (!$parent.length) {
+      $parent = $this.closest('.alert')
+    }
+
+    $parent.trigger(e = $.Event('close.bs.alert'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      // detach from parent, fire event then clean up data
+      $parent.detach().trigger('closed.bs.alert').remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent
+        .one('bsTransitionEnd', removeElement)
+        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
+      removeElement()
+  }
+
+
+  // ALERT PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.alert')
+
+      if (!data) $this.data('bs.alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.alert
+
+  $.fn.alert             = Plugin
+  $.fn.alert.Constructor = Alert
+
+
+  // ALERT NO CONFLICT
+  // =================
+
+  $.fn.alert.noConflict = function () {
+    $.fn.alert = old
+    return this
+  }
+
+
+  // ALERT DATA-API
+  // ==============
+
+  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.3.1
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // BUTTON PUBLIC CLASS DEFINITION
+  // ==============================
+
+  var Button = function (element, options) {
+    this.$element  = $(element)
+    this.options   = $.extend({}, Button.DEFAULTS, options)
+    this.isLoading = false
+  }
+
+  Button.VERSION  = '3.3.1'
+
+  Button.DEFAULTS = {
+    loadingText: 'loading...'
+  }
+
+  Button.prototype.setState = function (state) {
+    var d    = 'disabled'
+    var $el  = this.$element
+    var val  = $el.is('input') ? 'val' : 'html'
+    var data = $el.data()
+
+    state = state + 'Text'
+
+    if (data.resetText == null) $el.data('resetText', $el[val]())
+
+    // push to event loop to allow forms to submit
+    setTimeout($.proxy(function () {
+      $el[val](data[state] == null ? this.options[state] : data[state])
+
+      if (state == 'loadingText') {
+        this.isLoading = true
+        $el.addClass(d).attr(d, d)
+      } else if (this.isLoading) {
+        this.isLoading = false
+        $el.removeClass(d).removeAttr(d)
+      }
+    }, this), 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var changed = true
+    var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+    if ($parent.length) {
+      var $input = this.$element.find('input')
+      if ($input.prop('type') == 'radio') {
+        if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
+        else $parent.find('.active').removeClass('active')
+      }
+      if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
+    } else {
+      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+    }
+
+    if (changed) this.$element.toggleClass('active')
+  }
+
+
+  // BUTTON PLUGIN DEFINITION
+  // ========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.button')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  var old = $.fn.button
+
+  $.fn.button             = Plugin
+  $.fn.button.Constructor = Button
+
+
+  // BUTTON NO CONFLICT
+  // ==================
+
+  $.fn.button.noConflict = function () {
+    $.fn.button = old
+    return this
+  }
+
+
+  // BUTTON DATA-API
+  // ===============
+
+  $(document)
+    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+      var $btn = $(e.target)
+      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+      Plugin.call($btn, 'toggle')
+      e.preventDefault()
+    })
+    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+    })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.1
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // CAROUSEL CLASS DEFINITION
+  // =========================
+
+  var Carousel = function (element, options) {
+    this.$element    = $(element)
+    this.$indicators = this.$element.find('.carousel-indicators')
+    this.options     = options
+    this.paused      =
+    this.sliding     =
+    this.interval    =
+    this.$active     =
+    this.$items      = null
+
+    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
+
+    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
+      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
+      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
+  }
+
+  Carousel.VERSION  = '3.3.1'
+
+  Carousel.TRANSITION_DURATION = 600
+
+  Carousel.DEFAULTS = {
+    interval: 5000,
+    pause: 'hover',
+    wrap: true,
+    keyboard: true
+  }
+
+  Carousel.prototype.keydown = function (e) {
+    if (/input|textarea/i.test(e.target.tagName)) return
+    switch (e.which) {
+      case 37: this.prev(); break
+      case 39: this.next(); break
+      default: return
+    }
+
+    e.preventDefault()
+  }
+
+  Carousel.prototype.cycle = function (e) {
+    e || (this.paused = false)
+
+    this.interval && clearInterval(this.interval)
+
+    this.options.interval
+      && !this.paused
+      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+    return this
+  }
+
+  Carousel.prototype.getItemIndex = function (item) {
+    this.$items = item.parent().children('.item')
+    return this.$items.index(item || this.$active)
+  }
+
+  Carousel.prototype.getItemForDirection = function (direction, active) {
+    var delta = direction == 'prev' ? -1 : 1
+    var activeIndex = this.getItemIndex(active)
+    var itemIndex = (activeIndex + delta) % this.$items.length
+    return this.$items.eq(itemIndex)
+  }
+
+  Carousel.prototype.to = function (pos) {
+    var that        = this
+    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
+
+    if (pos > (this.$items.length - 1) || pos < 0) return
+
+    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
+    if (activeIndex == pos) return this.pause().cycle()
+
+    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
+  }
+
+  Carousel.prototype.pause = function (e) {
+    e || (this.paused = true)
+
+    if (this.$element.find('.next, .prev').length && $.support.transition) {
+      this.$element.trigger($.support.transition.end)
+      this.cycle(true)
+    }
+
+    this.interval = clearInterval(this.interval)
+
+    return this
+  }
+
+  Carousel.prototype.next = function () {
+    if (this.sliding) return
+    return this.slide('next')
+  }
+
+  Carousel.prototype.prev = function () {
+    if (this.sliding) return
+    return this.slide('prev')
+  }
+
+  Carousel.prototype.slide = function (type, next) {
+    var $active   = this.$element.find('.item.active')
+    var $next     = next || this.getItemForDirection(type, $active)
+    var isCycling = this.interval
+    var direction = type == 'next' ? 'left' : 'right'
+    var fallback  = type == 'next' ? 'first' : 'last'
+    var that      = this
+
+    if (!$next.length) {
+      if (!this.options.wrap) return
+      $next = this.$element.find('.item')[fallback]()
+    }
+
+    if ($next.hasClass('active')) return (this.sliding = false)
+
+    var relatedTarget = $next[0]
+    var slideEvent = $.Event('slide.bs.carousel', {
+      relatedTarget: relatedTarget,
+      direction: direction
+    })
+    this.$element.trigger(slideEvent)
+    if (slideEvent.isDefaultPrevented()) return
+
+    this.sliding = true
+
+    isCycling && this.pause()
+
+    if (this.$indicators.length) {
+      this.$indicators.find('.active').removeClass('active')
+      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
+      $nextIndicator && $nextIndicator.addClass('active')
+    }
+
+    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
+    if ($.support.transition && this.$element.hasClass('slide')) {
+      $next.addClass(type)
+      $next[0].offsetWidth // force reflow
+      $active.addClass(direction)
+      $next.addClass(direction)
+      $active
+        .one('bsTransitionEnd', function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () {
+            that.$element.trigger(slidEvent)
+          }, 0)
+        })
+        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
+    } else {
+      $active.removeClass('active')
+      $next.addClass('active')
+      this.sliding = false
+      this.$element.trigger(slidEvent)
+    }
+
+    isCycling && this.cycle()
+
+    return this
+  }
+
+
+  // CAROUSEL PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.carousel')
+      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+      var action  = typeof option == 'string' ? option : options.slide
+
+      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (action) data[action]()
+      else if (options.interval) data.pause().cycle()
+    })
+  }
+
+  var old = $.fn.carousel
+
+  $.fn.carousel             = Plugin
+  $.fn.carousel.Constructor = Carousel
+
+
+  // CAROUSEL NO CONFLICT
+  // ====================
+
+  $.fn.carousel.noConflict = function () {
+    $.fn.carousel = old
+    return this
+  }
+
+
+  // CAROUSEL DATA-API
+  // =================
+
+  var clickHandler = function (e) {
+    var href
+    var $this   = $(this)
+    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
+    if (!$target.hasClass('carousel')) return
+    var options = $.extend({}, $target.data(), $this.data())
+    var slideIndex = $this.attr('data-slide-to')
+    if (slideIndex) options.interval = false
+
+    Plugin.call($target, options)
+
+    if (slideIndex) {
+      $target.data('bs.carousel').to(slideIndex)
+    }
+
+    e.preventDefault()
+  }
+
+  $(document)
+    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
+    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
+
+  $(window).on('load', function () {
+    $('[data-ride="carousel"]').each(function () {
+      var $carousel = $(this)
+      Plugin.call($carousel, $carousel.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.3.1
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // COLLAPSE PUBLIC CLASS DEFINITION
+  // ================================
+
+  var Collapse = function (element, options) {
+    this.$element      = $(element)
+    this.options       = $.extend({}, Collapse.DEFAULTS, options)
+    this.$trigger      = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]')
+    this.transitioning = null
+
+    if (this.options.parent) {
+      this.$parent = this.getParent()
+    } else {
+      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
+    }
+
+    if (this.options.toggle) this.toggle()
+  }
+
+  Collapse.VERSION  = '3.3.1'
+
+  Collapse.TRANSITION_DURATION = 350
+
+  Collapse.DEFAULTS = {
+    toggle: true,
+    trigger: '[data-toggle="collapse"]'
+  }
+
+  Collapse.prototype.dimension = function () {
+    var hasWidth = this.$element.hasClass('width')
+    return hasWidth ? 'width' : 'height'
+  }
+
+  Collapse.prototype.show = function () {
+    if (this.transitioning || this.$element.hasClass('in')) return
+
+    var activesData
+    var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing')
+
+    if (actives && actives.length) {
+      activesData = actives.data('bs.collapse')
+      if (activesData && activesData.transitioning) return
+    }
+
+    var startEvent = $.Event('show.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    if (actives && actives.length) {
+      Plugin.call(actives, 'hide')
+      activesData || actives.data('bs.collapse', null)
+    }
+
+    var dimension = this.dimension()
+
+    this.$element
+      .removeClass('collapse')
+      .addClass('collapsing')[dimension](0)
+      .attr('aria-expanded', true)
+
+    this.$trigger
+      .removeClass('collapsed')
+      .attr('aria-expanded', true)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.$element
+        .removeClass('collapsing')
+        .addClass('collapse in')[dimension]('')
+      this.transitioning = 0
+      this.$element
+        .trigger('shown.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+    this.$element
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
+  }
+
+  Collapse.prototype.hide = function () {
+    if (this.transitioning || !this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('hide.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var dimension = this.dimension()
+
+    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
+
+    this.$element
+      .addClass('collapsing')
+      .removeClass('collapse in')
+      .attr('aria-expanded', false)
+
+    this.$trigger
+      .addClass('collapsed')
+      .attr('aria-expanded', false)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.transitioning = 0
+      this.$element
+        .removeClass('collapsing')
+        .addClass('collapse')
+        .trigger('hidden.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    this.$element
+      [dimension](0)
+      .one('bsTransitionEnd', $.proxy(complete, this))
+      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
+  }
+
+  Collapse.prototype.toggle = function () {
+    this[this.$element.hasClass('in') ? 'hide' : 'show']()
+  }
+
+  Collapse.prototype.getParent = function () {
+    return $(this.options.parent)
+      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
+      .each($.proxy(function (i, element) {
+        var $element = $(element)
+        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
+      }, this))
+      .end()
+  }
+
+  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
+    var isOpen = $element.hasClass('in')
+
+    $element.attr('aria-expanded', isOpen)
+    $trigger
+      .toggleClass('collapsed', !isOpen)
+      .attr('aria-expanded', isOpen)
+  }
+
+  function getTargetFromTrigger($trigger) {
+    var href
+    var target = $trigger.attr('data-target')
+      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
+
+    return $(target)
+  }
+
+
+  // COLLAPSE PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.collapse')
+      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data && options.toggle && option == 'show') options.toggle = false
+      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.collapse
+
+  $.fn.collapse             = Plugin
+  $.fn.collapse.Constructor = Collapse
+
+
+  // COLLAPSE NO CONFLICT
+  // ====================
+
+  $.fn.collapse.noConflict = function () {
+    $.fn.collapse = old
+    return this
+  }
+
+
+  // COLLAPSE DATA-API
+  // =================
+
+  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
+    var $this   = $(this)
+
+    if (!$this.attr('data-target')) e.preventDefault()
+
+    var $target = getTargetFromTrigger($this)
+    var data    = $target.data('bs.collapse')
+    var option  = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this })
+
+    Plugin.call($target, option)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.1
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // DROPDOWN CLASS DEFINITION
+  // =========================
+
+  var backdrop = '.dropdown-backdrop'
+  var toggle   = '[data-toggle="dropdown"]'
+  var Dropdown = function (element) {
+    $(element).on('click.bs.dropdown', this.toggle)
+  }
+
+  Dropdown.VERSION = '3.3.1'
+
+  Dropdown.prototype.toggle = function (e) {
+    var $this = $(this)
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    clearMenus()
+
+    if (!isActive) {
+      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+        // if mobile we use a backdrop because click events don't delegate
+        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
+      }
+
+      var relatedTarget = { relatedTarget: this }
+      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+      if (e.isDefaultPrevented()) return
+
+      $this
+        .trigger('focus')
+        .attr('aria-expanded', 'true')
+
+      $parent
+        .toggleClass('open')
+        .trigger('shown.bs.dropdown', relatedTarget)
+    }
+
+    return false
+  }
+
+  Dropdown.prototype.keydown = function (e) {
+    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+    var $this = $(this)
+
+    e.preventDefault()
+    e.stopPropagation()
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {
+      if (e.which == 27) $parent.find(toggle).trigger('focus')
+      return $this.trigger('click')
+    }
+
+    var desc = ' li:not(.divider):visible a'
+    var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
+
+    if (!$items.length) return
+
+    var index = $items.index(e.target)
+
+    if (e.which == 38 && index > 0)                 index--                        // up
+    if (e.which == 40 && index < $items.length - 1) index++                        // down
+    if (!~index)                                      index = 0
+
+    $items.eq(index).trigger('focus')
+  }
+
+  function clearMenus(e) {
+    if (e && e.which === 3) return
+    $(backdrop).remove()
+    $(toggle).each(function () {
+      var $this         = $(this)
+      var $parent       = getParent($this)
+      var relatedTarget = { relatedTarget: this }
+
+      if (!$parent.hasClass('open')) return
+
+      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+      if (e.isDefaultPrevented()) return
+
+      $this.attr('aria-expanded', 'false')
+      $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+    })
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    var $parent = selector && $(selector)
+
+    return $parent && $parent.length ? $parent : $this.parent()
+  }
+
+
+  // DROPDOWN PLUGIN DEFINITION
+  // ==========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.dropdown')
+
+      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  var old = $.fn.dropdown
+
+  $.fn.dropdown             = Plugin
+  $.fn.dropdown.Constructor = Dropdown
+
+
+  // DROPDOWN NO CONFLICT
+  // ====================
+
+  $.fn.dropdown.noConflict = function () {
+    $.fn.dropdown = old
+    return this
+  }
+
+
+  // APPLY TO STANDARD DROPDOWN ELEMENTS
+  // ===================================
+
+  $(document)
+    .on('click.bs.dropdown.data-api', clearMenus)
+    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+    .on('keydown.bs.dropdown.data-api', '[role="menu"]', Dropdown.prototype.keydown)
+    .on('keydown.bs.dropdown.data-api', '[role="listbox"]', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.1
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // MODAL CLASS DEFINITION
+  // ======================
+
+  var Modal = function (element, options) {
+    this.options        = options
+    this.$body          = $(document.body)
+    this.$element       = $(element)
+    this.$backdrop      =
+    this.isShown        = null
+    this.scrollbarWidth = 0
+
+    if (this.options.remote) {
+      this.$element
+        .find('.modal-content')
+        .load(this.options.remote, $.proxy(function () {
+          this.$element.trigger('loaded.bs.modal')
+        }, this))
+    }
+  }
+
+  Modal.VERSION  = '3.3.1'
+
+  Modal.TRANSITION_DURATION = 300
+  Modal.BACKDROP_TRANSITION_DURATION = 150
+
+  Modal.DEFAULTS = {
+    backdrop: true,
+    keyboard: true,
+    show: true
+  }
+
+  Modal.prototype.toggle = function (_relatedTarget) {
+    return this.isShown ? this.hide() : this.show(_relatedTarget)
+  }
+
+  Modal.prototype.show = function (_relatedTarget) {
+    var that = this
+    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+    this.$element.trigger(e)
+
+    if (this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = true
+
+    this.checkScrollbar()
+    this.setScrollbar()
+    this.$body.addClass('modal-open')
+
+    this.escape()
+    this.resize()
+
+    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+    this.backdrop(function () {
+      var transition = $.support.transition && that.$element.hasClass('fade')
+
+      if (!that.$element.parent().length) {
+        that.$element.appendTo(that.$body) // don't move modals dom position
+      }
+
+      that.$element
+        .show()
+        .scrollTop(0)
+
+      if (that.options.backdrop) that.adjustBackdrop()
+      that.adjustDialog()
+
+      if (transition) {
+        that.$element[0].offsetWidth // force reflow
+      }
+
+      that.$element
+        .addClass('in')
+        .attr('aria-hidden', false)
+
+      that.enforceFocus()
+
+      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+      transition ?
+        that.$element.find('.modal-dialog') // wait for modal to slide in
+          .one('bsTransitionEnd', function () {
+            that.$element.trigger('focus').trigger(e)
+          })
+          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+        that.$element.trigger('focus').trigger(e)
+    })
+  }
+
+  Modal.prototype.hide = function (e) {
+    if (e) e.preventDefault()
+
+    e = $.Event('hide.bs.modal')
+
+    this.$element.trigger(e)
+
+    if (!this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = false
+
+    this.escape()
+    this.resize()
+
+    $(document).off('focusin.bs.modal')
+
+    this.$element
+      .removeClass('in')
+      .attr('aria-hidden', true)
+      .off('click.dismiss.bs.modal')
+
+    $.support.transition && this.$element.hasClass('fade') ?
+      this.$element
+        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+      this.hideModal()
+  }
+
+  Modal.prototype.enforceFocus = function () {
+    $(document)
+      .off('focusin.bs.modal') // guard against infinite focus loop
+      .on('focusin.bs.modal', $.proxy(function (e) {
+        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+          this.$element.trigger('focus')
+        }
+      }, this))
+  }
+
+  Modal.prototype.escape = function () {
+    if (this.isShown && this.options.keyboard) {
+      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+        e.which == 27 && this.hide()
+      }, this))
+    } else if (!this.isShown) {
+      this.$element.off('keydown.dismiss.bs.modal')
+    }
+  }
+
+  Modal.prototype.resize = function () {
+    if (this.isShown) {
+      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+    } else {
+      $(window).off('resize.bs.modal')
+    }
+  }
+
+  Modal.prototype.hideModal = function () {
+    var that = this
+    this.$element.hide()
+    this.backdrop(function () {
+      that.$body.removeClass('modal-open')
+      that.resetAdjustments()
+      that.resetScrollbar()
+      that.$element.trigger('hidden.bs.modal')
+    })
+  }
+
+  Modal.prototype.removeBackdrop = function () {
+    this.$backdrop && this.$backdrop.remove()
+    this.$backdrop = null
+  }
+
+  Modal.prototype.backdrop = function (callback) {
+    var that = this
+    var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+    if (this.isShown && this.options.backdrop) {
+      var doAnimate = $.support.transition && animate
+
+      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+        .prependTo(this.$element)
+        .on('click.dismiss.bs.modal', $.proxy(function (e) {
+          if (e.target !== e.currentTarget) return
+          this.options.backdrop == 'static'
+            ? this.$element[0].focus.call(this.$element[0])
+            : this.hide.call(this)
+        }, this))
+
+      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+      this.$backdrop.addClass('in')
+
+      if (!callback) return
+
+      doAnimate ?
+        this.$backdrop
+          .one('bsTransitionEnd', callback)
+          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+        callback()
+
+    } else if (!this.isShown && this.$backdrop) {
+      this.$backdrop.removeClass('in')
+
+      var callbackRemove = function () {
+        that.removeBackdrop()
+        callback && callback()
+      }
+      $.support.transition && this.$element.hasClass('fade') ?
+        this.$backdrop
+          .one('bsTransitionEnd', callbackRemove)
+          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+        callbackRemove()
+
+    } else if (callback) {
+      callback()
+    }
+  }
+
+  // these following methods are used to handle overflowing modals
+
+  Modal.prototype.handleUpdate = function () {
+    if (this.options.backdrop) this.adjustBackdrop()
+    this.adjustDialog()
+  }
+
+  Modal.prototype.adjustBackdrop = function () {
+    this.$backdrop
+      .css('height', 0)
+      .css('height', this.$element[0].scrollHeight)
+  }
+
+  Modal.prototype.adjustDialog = function () {
+    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+    this.$element.css({
+      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+    })
+  }
+
+  Modal.prototype.resetAdjustments = function () {
+    this.$element.css({
+      paddingLeft: '',
+      paddingRight: ''
+    })
+  }
+
+  Modal.prototype.checkScrollbar = function () {
+    this.bodyIsOverflowing = document.body.scrollHeight > document.documentElement.clientHeight
+    this.scrollbarWidth = this.measureScrollbar()
+  }
+
+  Modal.prototype.setScrollbar = function () {
+    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+  }
+
+  Modal.prototype.resetScrollbar = function () {
+    this.$body.css('padding-right', '')
+  }
+
+  Modal.prototype.measureScrollbar = function () { // thx walsh
+    var scrollDiv = document.createElement('div')
+    scrollDiv.className = 'modal-scrollbar-measure'
+    this.$body.append(scrollDiv)
+    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+    this.$body[0].removeChild(scrollDiv)
+    return scrollbarWidth
+  }
+
+
+  // MODAL PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option, _relatedTarget) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.modal')
+      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option](_relatedTarget)
+      else if (options.show) data.show(_relatedTarget)
+    })
+  }
+
+  var old = $.fn.modal
+
+  $.fn.modal             = Plugin
+  $.fn.modal.Constructor = Modal
+
+
+  // MODAL NO CONFLICT
+  // =================
+
+  $.fn.modal.noConflict = function () {
+    $.fn.modal = old
+    return this
+  }
+
+
+  // MODAL DATA-API
+  // ==============
+
+  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+    var $this   = $(this)
+    var href    = $this.attr('href')
+    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+    if ($this.is('a')) e.preventDefault()
+
+    $target.one('show.bs.modal', function (showEvent) {
+      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+      $target.one('hidden.bs.modal', function () {
+        $this.is(':visible') && $this.trigger('focus')
+      })
+    })
+    Plugin.call($target, option, this)
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.1
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.VERSION  = '3.3.1'
+
+  Tooltip.TRANSITION_DURATION = 150
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false,
+    viewport: {
+      selector: 'body',
+      padding: 0
+    }
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled   = true
+    this.type      = type
+    this.$element  = $(element)
+    this.options   = this.getOptions(options)
+    this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (self && self.$tip && self.$tip.is(':visible')) {
+      self.hoverState = 'in'
+      return
+    }
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget).data('bs.' + this.type)
+
+    if (!self) {
+      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+      $(obj.currentTarget).data('bs.' + this.type, self)
+    }
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+      if (e.isDefaultPrevented() || !inDom) return
+      var that = this
+
+      var $tip = this.tip()
+
+      var tipId = this.getUID(this.type)
+
+      this.setContent()
+      $tip.attr('id', tipId)
+      this.$element.attr('aria-describedby', tipId)
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+        .data('bs.' + this.type, this)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var orgPlacement = placement
+        var $container   = this.options.container ? $(this.options.container) : this.$element.parent()
+        var containerDim = this.getPosition($container)
+
+        placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top'    :
+                    placement == 'top'    && pos.top    - actualHeight < containerDim.top    ? 'bottom' :
+                    placement == 'right'  && pos.right  + actualWidth  > containerDim.width  ? 'left'   :
+                    placement == 'left'   && pos.left   - actualWidth  < containerDim.left   ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+
+      var complete = function () {
+        var prevHoverState = that.hoverState
+        that.$element.trigger('shown.bs.' + that.type)
+        that.hoverState = null
+
+        if (prevHoverState == 'out') that.leave(that)
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one('bsTransitionEnd', complete)
+          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      offset.top = offset.top + height - actualHeight
+    }
+
+    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+    if (delta.left) offset.left += delta.left
+    else offset.top += delta.top
+
+    var isVertical          = /top|bottom/.test(placement)
+    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+    $tip.offset(offset)
+    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, isHorizontal) {
+    this.arrow()
+      .css(isHorizontal ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+      .css(isHorizontal ? 'top' : 'left', '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function (callback) {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element
+        .removeAttr('aria-describedby')
+        .trigger('hidden.bs.' + that.type)
+      callback && callback()
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one('bsTransitionEnd', complete)
+        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function ($element) {
+    $element   = $element || this.$element
+
+    var el     = $element[0]
+    var isBody = el.tagName == 'BODY'
+
+    var elRect    = el.getBoundingClientRect()
+    if (elRect.width == null) {
+      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+    }
+    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
+    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+    return $.extend({}, elRect, scroll, outerDims, elOffset)
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+
+  }
+
+  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+    var delta = { top: 0, left: 0 }
+    if (!this.$viewport) return delta
+
+    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+    var viewportDimensions = this.getPosition(this.$viewport)
+
+    if (/right|left/.test(placement)) {
+      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
+      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+      if (topEdgeOffset < viewportDimensions.top) { // top overflow
+        delta.top = viewportDimensions.top - topEdgeOffset
+      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+      }
+    } else {
+      var leftEdgeOffset  = pos.left - viewportPadding
+      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+        delta.left = viewportDimensions.left - leftEdgeOffset
+      } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+      }
+    }
+
+    return delta
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.getUID = function (prefix) {
+    do prefix += ~~(Math.random() * 1000000)
+    while (document.getElementById(prefix))
+    return prefix
+  }
+
+  Tooltip.prototype.tip = function () {
+    return (this.$tip = this.$tip || $(this.options.template))
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = this
+    if (e) {
+      self = $(e.currentTarget).data('bs.' + this.type)
+      if (!self) {
+        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+        $(e.currentTarget).data('bs.' + this.type, self)
+      }
+    }
+
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    var that = this
+    clearTimeout(this.timeout)
+    this.hide(function () {
+      that.$element.off('.' + that.type).removeData('bs.' + that.type)
+    })
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this    = $(this)
+      var data     = $this.data('bs.tooltip')
+      var options  = typeof option == 'object' && option
+      var selector = options && options.selector
+
+      if (!data && option == 'destroy') return
+      if (selector) {
+        if (!data) $this.data('bs.tooltip', (data = {}))
+        if (!data[selector]) data[selector] = new Tooltip(this, options)
+      } else {
+        if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      }
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip             = Plugin
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.1
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.VERSION  = '3.3.1'
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this    = $(this)
+      var data     = $this.data('bs.popover')
+      var options  = typeof option == 'object' && option
+      var selector = options && options.selector
+
+      if (!data && option == 'destroy') return
+      if (selector) {
+        if (!data) $this.data('bs.popover', (data = {}))
+        if (!data[selector]) data[selector] = new Popover(this, options)
+      } else {
+        if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      }
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.popover
+
+  $.fn.popover             = Plugin
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.1
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // SCROLLSPY CLASS DEFINITION
+  // ==========================
+
+  function ScrollSpy(element, options) {
+    var process  = $.proxy(this.process, this)
+
+    this.$body          = $('body')
+    this.$scrollElement = $(element).is('body') ? $(window) : $(element)
+    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
+    this.selector       = (this.options.target || '') + ' .nav li > a'
+    this.offsets        = []
+    this.targets        = []
+    this.activeTarget   = null
+    this.scrollHeight   = 0
+
+    this.$scrollElement.on('scroll.bs.scrollspy', process)
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.VERSION  = '3.3.1'
+
+  ScrollSpy.DEFAULTS = {
+    offset: 10
+  }
+
+  ScrollSpy.prototype.getScrollHeight = function () {
+    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+  }
+
+  ScrollSpy.prototype.refresh = function () {
+    var offsetMethod = 'offset'
+    var offsetBase   = 0
+
+    if (!$.isWindow(this.$scrollElement[0])) {
+      offsetMethod = 'position'
+      offsetBase   = this.$scrollElement.scrollTop()
+    }
+
+    this.offsets = []
+    this.targets = []
+    this.scrollHeight = this.getScrollHeight()
+
+    var self     = this
+
+    this.$body
+      .find(this.selector)
+      .map(function () {
+        var $el   = $(this)
+        var href  = $el.data('target') || $el.attr('href')
+        var $href = /^#./.test(href) && $(href)
+
+        return ($href
+          && $href.length
+          && $href.is(':visible')
+          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+      })
+      .sort(function (a, b) { return a[0] - b[0] })
+      .each(function () {
+        self.offsets.push(this[0])
+        self.targets.push(this[1])
+      })
+  }
+
+  ScrollSpy.prototype.process = function () {
+    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
+    var scrollHeight = this.getScrollHeight()
+    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
+    var offsets      = this.offsets
+    var targets      = this.targets
+    var activeTarget = this.activeTarget
+    var i
+
+    if (this.scrollHeight != scrollHeight) {
+      this.refresh()
+    }
+
+    if (scrollTop >= maxScroll) {
+      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+    }
+
+    if (activeTarget && scrollTop < offsets[0]) {
+      this.activeTarget = null
+      return this.clear()
+    }
+
+    for (i = offsets.length; i--;) {
+      activeTarget != targets[i]
+        && scrollTop >= offsets[i]
+        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+        && this.activate(targets[i])
+    }
+  }
+
+  ScrollSpy.prototype.activate = function (target) {
+    this.activeTarget = target
+
+    this.clear()
+
+    var selector = this.selector +
+        '[data-target="' + target + '"],' +
+        this.selector + '[href="' + target + '"]'
+
+    var active = $(selector)
+      .parents('li')
+      .addClass('active')
+
+    if (active.parent('.dropdown-menu').length) {
+      active = active
+        .closest('li.dropdown')
+        .addClass('active')
+    }
+
+    active.trigger('activate.bs.scrollspy')
+  }
+
+  ScrollSpy.prototype.clear = function () {
+    $(this.selector)
+      .parentsUntil(this.options.target, '.active')
+      .removeClass('active')
+  }
+
+
+  // SCROLLSPY PLUGIN DEFINITION
+  // ===========================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.scrollspy')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy             = Plugin
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+
+  // SCROLLSPY NO CONFLICT
+  // =====================
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+  // SCROLLSPY DATA-API
+  // ==================
+
+  $(window).on('load.bs.scrollspy.data-api', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      Plugin.call($spy, $spy.data())
+    })
+  })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.1
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TAB CLASS DEFINITION
+  // ====================
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.VERSION = '3.3.1'
+
+  Tab.TRANSITION_DURATION = 150
+
+  Tab.prototype.show = function () {
+    var $this    = this.element
+    var $ul      = $this.closest('ul:not(.dropdown-menu)')
+    var selector = $this.data('target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    if ($this.parent('li').hasClass('active')) return
+
+    var $previous = $ul.find('.active:last a')
+    var hideEvent = $.Event('hide.bs.tab', {
+      relatedTarget: $this[0]
+    })
+    var showEvent = $.Event('show.bs.tab', {
+      relatedTarget: $previous[0]
+    })
+
+    $previous.trigger(hideEvent)
+    $this.trigger(showEvent)
+
+    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+    var $target = $(selector)
+
+    this.activate($this.closest('li'), $ul)
+    this.activate($target, $target.parent(), function () {
+      $previous.trigger({
+        type: 'hidden.bs.tab',
+        relatedTarget: $this[0]
+      })
+      $this.trigger({
+        type: 'shown.bs.tab',
+        relatedTarget: $previous[0]
+      })
+    })
+  }
+
+  Tab.prototype.activate = function (element, container, callback) {
+    var $active    = container.find('> .active')
+    var transition = callback
+      && $.support.transition
+      && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)
+
+    function next() {
+      $active
+        .removeClass('active')
+        .find('> .dropdown-menu > .active')
+          .removeClass('active')
+        .end()
+        .find('[data-toggle="tab"]')
+          .attr('aria-expanded', false)
+
+      element
+        .addClass('active')
+        .find('[data-toggle="tab"]')
+          .attr('aria-expanded', true)
+
+      if (transition) {
+        element[0].offsetWidth // reflow for transition
+        element.addClass('in')
+      } else {
+        element.removeClass('fade')
+      }
+
+      if (element.parent('.dropdown-menu')) {
+        element
+          .closest('li.dropdown')
+            .addClass('active')
+          .end()
+          .find('[data-toggle="tab"]')
+            .attr('aria-expanded', true)
+      }
+
+      callback && callback()
+    }
+
+    $active.length && transition ?
+      $active
+        .one('bsTransitionEnd', next)
+        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+      next()
+
+    $active.removeClass('in')
+  }
+
+
+  // TAB PLUGIN DEFINITION
+  // =====================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.tab')
+
+      if (!data) $this.data('bs.tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.tab
+
+  $.fn.tab             = Plugin
+  $.fn.tab.Constructor = Tab
+
+
+  // TAB NO CONFLICT
+  // ===============
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+  // TAB DATA-API
+  // ============
+
+  var clickHandler = function (e) {
+    e.preventDefault()
+    Plugin.call($(this), 'show')
+  }
+
+  $(document)
+    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.1
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // AFFIX CLASS DEFINITION
+  // ======================
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, Affix.DEFAULTS, options)
+
+    this.$target = $(this.options.target)
+      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
+
+    this.$element     = $(element)
+    this.affixed      =
+    this.unpin        =
+    this.pinnedOffset = null
+
+    this.checkPosition()
+  }
+
+  Affix.VERSION  = '3.3.1'
+
+  Affix.RESET    = 'affix affix-top affix-bottom'
+
+  Affix.DEFAULTS = {
+    offset: 0,
+    target: window
+  }
+
+  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+    var scrollTop    = this.$target.scrollTop()
+    var position     = this.$element.offset()
+    var targetHeight = this.$target.height()
+
+    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+    if (this.affixed == 'bottom') {
+      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+    }
+
+    var initializing   = this.affixed == null
+    var colliderTop    = initializing ? scrollTop : position.top
+    var colliderHeight = initializing ? targetHeight : height
+
+    if (offsetTop != null && colliderTop <= offsetTop) return 'top'
+    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+    return false
+  }
+
+  Affix.prototype.getPinnedOffset = function () {
+    if (this.pinnedOffset) return this.pinnedOffset
+    this.$element.removeClass(Affix.RESET).addClass('affix')
+    var scrollTop = this.$target.scrollTop()
+    var position  = this.$element.offset()
+    return (this.pinnedOffset = position.top - scrollTop)
+  }
+
+  Affix.prototype.checkPositionWithEventLoop = function () {
+    setTimeout($.proxy(this.checkPosition, this), 1)
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var height       = this.$element.height()
+    var offset       = this.options.offset
+    var offsetTop    = offset.top
+    var offsetBottom = offset.bottom
+    var scrollHeight = $('body').height()
+
+    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+    if (this.affixed != affix) {
+      if (this.unpin != null) this.$element.css('top', '')
+
+      var affixType = 'affix' + (affix ? '-' + affix : '')
+      var e         = $.Event(affixType + '.bs.affix')
+
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+
+      this.affixed = affix
+      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+      this.$element
+        .removeClass(Affix.RESET)
+        .addClass(affixType)
+        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+    }
+
+    if (affix == 'bottom') {
+      this.$element.offset({
+        top: scrollHeight - height - offsetBottom
+      })
+    }
+  }
+
+
+  // AFFIX PLUGIN DEFINITION
+  // =======================
+
+  function Plugin(option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.affix')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  var old = $.fn.affix
+
+  $.fn.affix             = Plugin
+  $.fn.affix.Constructor = Affix
+
+
+  // AFFIX NO CONFLICT
+  // =================
+
+  $.fn.affix.noConflict = function () {
+    $.fn.affix = old
+    return this
+  }
+
+
+  // AFFIX DATA-API
+  // ==============
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+      var data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
+
+      Plugin.call($spy, data)
+    })
+  })
+
+}(jQuery);
diff --git a/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.min.js b/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.min.js
new file mode 100644
index 0000000..d839865
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/bootstrap/js/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"tran [...]
+})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active" [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/css/font-awesome.css b/dicoogle/src/main/resources/webapp/css/font-awesome.css
new file mode 100644
index 0000000..2dcdc22
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/font-awesome.css
@@ -0,0 +1,1801 @@
+/*!
+ *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */
+/* FONT PATH
+ * -------------------------- */
+ at font-face {
+  font-family: 'FontAwesome';
+  src: url('../fonts/fontawesome-webfont.eot?v=4.3.0');
+  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+.fa {
+  display: inline-block;
+  font: normal normal normal 14px/1 FontAwesome;
+  font-size: inherit;
+  text-rendering: auto;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  transform: translate(0, 0);
+}
+/* makes the font 33% larger relative to the icon container */
+.fa-lg {
+  font-size: 1.33333333em;
+  line-height: 0.75em;
+  vertical-align: -15%;
+}
+.fa-2x {
+  font-size: 2em;
+}
+.fa-3x {
+  font-size: 3em;
+}
+.fa-4x {
+  font-size: 4em;
+}
+.fa-5x {
+  font-size: 5em;
+}
+.fa-fw {
+  width: 1.28571429em;
+  text-align: center;
+}
+.fa-ul {
+  padding-left: 0;
+  margin-left: 2.14285714em;
+  list-style-type: none;
+}
+.fa-ul > li {
+  position: relative;
+}
+.fa-li {
+  position: absolute;
+  left: -2.14285714em;
+  width: 2.14285714em;
+  top: 0.14285714em;
+  text-align: center;
+}
+.fa-li.fa-lg {
+  left: -1.85714286em;
+}
+.fa-border {
+  padding: .2em .25em .15em;
+  border: solid 0.08em #eeeeee;
+  border-radius: .1em;
+}
+.pull-right {
+  float: right;
+}
+.pull-left {
+  float: left;
+}
+.fa.pull-left {
+  margin-right: .3em;
+}
+.fa.pull-right {
+  margin-left: .3em;
+}
+.fa-spin {
+  -webkit-animation: fa-spin 2s infinite linear;
+  animation: fa-spin 2s infinite linear;
+}
+.fa-pulse {
+  -webkit-animation: fa-spin 1s infinite steps(8);
+  animation: fa-spin 1s infinite steps(8);
+}
+ at -webkit-keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+ at keyframes fa-spin {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+.fa-rotate-90 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
+  -webkit-transform: rotate(90deg);
+  -ms-transform: rotate(90deg);
+  transform: rotate(90deg);
+}
+.fa-rotate-180 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
+  -webkit-transform: rotate(180deg);
+  -ms-transform: rotate(180deg);
+  transform: rotate(180deg);
+}
+.fa-rotate-270 {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+  -webkit-transform: rotate(270deg);
+  -ms-transform: rotate(270deg);
+  transform: rotate(270deg);
+}
+.fa-flip-horizontal {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
+  -webkit-transform: scale(-1, 1);
+  -ms-transform: scale(-1, 1);
+  transform: scale(-1, 1);
+}
+.fa-flip-vertical {
+  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
+  -webkit-transform: scale(1, -1);
+  -ms-transform: scale(1, -1);
+  transform: scale(1, -1);
+}
+:root .fa-rotate-90,
+:root .fa-rotate-180,
+:root .fa-rotate-270,
+:root .fa-flip-horizontal,
+:root .fa-flip-vertical {
+  filter: none;
+}
+.fa-stack {
+  position: relative;
+  display: inline-block;
+  width: 2em;
+  height: 2em;
+  line-height: 2em;
+  vertical-align: middle;
+}
+.fa-stack-1x,
+.fa-stack-2x {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  text-align: center;
+}
+.fa-stack-1x {
+  line-height: inherit;
+}
+.fa-stack-2x {
+  font-size: 2em;
+}
+.fa-inverse {
+  color: #ffffff;
+}
+/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen
+   readers do not read off random characters that represent icons */
+.fa-glass:before {
+  content: "\f000";
+}
+.fa-music:before {
+  content: "\f001";
+}
+.fa-search:before {
+  content: "\f002";
+}
+.fa-envelope-o:before {
+  content: "\f003";
+}
+.fa-heart:before {
+  content: "\f004";
+}
+.fa-star:before {
+  content: "\f005";
+}
+.fa-star-o:before {
+  content: "\f006";
+}
+.fa-user:before {
+  content: "\f007";
+}
+.fa-film:before {
+  content: "\f008";
+}
+.fa-th-large:before {
+  content: "\f009";
+}
+.fa-th:before {
+  content: "\f00a";
+}
+.fa-th-list:before {
+  content: "\f00b";
+}
+.fa-check:before {
+  content: "\f00c";
+}
+.fa-remove:before,
+.fa-close:before,
+.fa-times:before {
+  content: "\f00d";
+}
+.fa-search-plus:before {
+  content: "\f00e";
+}
+.fa-search-minus:before {
+  content: "\f010";
+}
+.fa-power-off:before {
+  content: "\f011";
+}
+.fa-signal:before {
+  content: "\f012";
+}
+.fa-gear:before,
+.fa-cog:before {
+  content: "\f013";
+}
+.fa-trash-o:before {
+  content: "\f014";
+}
+.fa-home:before {
+  content: "\f015";
+}
+.fa-file-o:before {
+  content: "\f016";
+}
+.fa-clock-o:before {
+  content: "\f017";
+}
+.fa-road:before {
+  content: "\f018";
+}
+.fa-download:before {
+  content: "\f019";
+}
+.fa-arrow-circle-o-down:before {
+  content: "\f01a";
+}
+.fa-arrow-circle-o-up:before {
+  content: "\f01b";
+}
+.fa-inbox:before {
+  content: "\f01c";
+}
+.fa-play-circle-o:before {
+  content: "\f01d";
+}
+.fa-rotate-right:before,
+.fa-repeat:before {
+  content: "\f01e";
+}
+.fa-refresh:before {
+  content: "\f021";
+}
+.fa-list-alt:before {
+  content: "\f022";
+}
+.fa-lock:before {
+  content: "\f023";
+}
+.fa-flag:before {
+  content: "\f024";
+}
+.fa-headphones:before {
+  content: "\f025";
+}
+.fa-volume-off:before {
+  content: "\f026";
+}
+.fa-volume-down:before {
+  content: "\f027";
+}
+.fa-volume-up:before {
+  content: "\f028";
+}
+.fa-qrcode:before {
+  content: "\f029";
+}
+.fa-barcode:before {
+  content: "\f02a";
+}
+.fa-tag:before {
+  content: "\f02b";
+}
+.fa-tags:before {
+  content: "\f02c";
+}
+.fa-book:before {
+  content: "\f02d";
+}
+.fa-bookmark:before {
+  content: "\f02e";
+}
+.fa-print:before {
+  content: "\f02f";
+}
+.fa-camera:before {
+  content: "\f030";
+}
+.fa-font:before {
+  content: "\f031";
+}
+.fa-bold:before {
+  content: "\f032";
+}
+.fa-italic:before {
+  content: "\f033";
+}
+.fa-text-height:before {
+  content: "\f034";
+}
+.fa-text-width:before {
+  content: "\f035";
+}
+.fa-align-left:before {
+  content: "\f036";
+}
+.fa-align-center:before {
+  content: "\f037";
+}
+.fa-align-right:before {
+  content: "\f038";
+}
+.fa-align-justify:before {
+  content: "\f039";
+}
+.fa-list:before {
+  content: "\f03a";
+}
+.fa-dedent:before,
+.fa-outdent:before {
+  content: "\f03b";
+}
+.fa-indent:before {
+  content: "\f03c";
+}
+.fa-video-camera:before {
+  content: "\f03d";
+}
+.fa-photo:before,
+.fa-image:before,
+.fa-picture-o:before {
+  content: "\f03e";
+}
+.fa-pencil:before {
+  content: "\f040";
+}
+.fa-map-marker:before {
+  content: "\f041";
+}
+.fa-adjust:before {
+  content: "\f042";
+}
+.fa-tint:before {
+  content: "\f043";
+}
+.fa-edit:before,
+.fa-pencil-square-o:before {
+  content: "\f044";
+}
+.fa-share-square-o:before {
+  content: "\f045";
+}
+.fa-check-square-o:before {
+  content: "\f046";
+}
+.fa-arrows:before {
+  content: "\f047";
+}
+.fa-step-backward:before {
+  content: "\f048";
+}
+.fa-fast-backward:before {
+  content: "\f049";
+}
+.fa-backward:before {
+  content: "\f04a";
+}
+.fa-play:before {
+  content: "\f04b";
+}
+.fa-pause:before {
+  content: "\f04c";
+}
+.fa-stop:before {
+  content: "\f04d";
+}
+.fa-forward:before {
+  content: "\f04e";
+}
+.fa-fast-forward:before {
+  content: "\f050";
+}
+.fa-step-forward:before {
+  content: "\f051";
+}
+.fa-eject:before {
+  content: "\f052";
+}
+.fa-chevron-left:before {
+  content: "\f053";
+}
+.fa-chevron-right:before {
+  content: "\f054";
+}
+.fa-plus-circle:before {
+  content: "\f055";
+}
+.fa-minus-circle:before {
+  content: "\f056";
+}
+.fa-times-circle:before {
+  content: "\f057";
+}
+.fa-check-circle:before {
+  content: "\f058";
+}
+.fa-question-circle:before {
+  content: "\f059";
+}
+.fa-info-circle:before {
+  content: "\f05a";
+}
+.fa-crosshairs:before {
+  content: "\f05b";
+}
+.fa-times-circle-o:before {
+  content: "\f05c";
+}
+.fa-check-circle-o:before {
+  content: "\f05d";
+}
+.fa-ban:before {
+  content: "\f05e";
+}
+.fa-arrow-left:before {
+  content: "\f060";
+}
+.fa-arrow-right:before {
+  content: "\f061";
+}
+.fa-arrow-up:before {
+  content: "\f062";
+}
+.fa-arrow-down:before {
+  content: "\f063";
+}
+.fa-mail-forward:before,
+.fa-share:before {
+  content: "\f064";
+}
+.fa-expand:before {
+  content: "\f065";
+}
+.fa-compress:before {
+  content: "\f066";
+}
+.fa-plus:before {
+  content: "\f067";
+}
+.fa-minus:before {
+  content: "\f068";
+}
+.fa-asterisk:before {
+  content: "\f069";
+}
+.fa-exclamation-circle:before {
+  content: "\f06a";
+}
+.fa-gift:before {
+  content: "\f06b";
+}
+.fa-leaf:before {
+  content: "\f06c";
+}
+.fa-fire:before {
+  content: "\f06d";
+}
+.fa-eye:before {
+  content: "\f06e";
+}
+.fa-eye-slash:before {
+  content: "\f070";
+}
+.fa-warning:before,
+.fa-exclamation-triangle:before {
+  content: "\f071";
+}
+.fa-plane:before {
+  content: "\f072";
+}
+.fa-calendar:before {
+  content: "\f073";
+}
+.fa-random:before {
+  content: "\f074";
+}
+.fa-comment:before {
+  content: "\f075";
+}
+.fa-magnet:before {
+  content: "\f076";
+}
+.fa-chevron-up:before {
+  content: "\f077";
+}
+.fa-chevron-down:before {
+  content: "\f078";
+}
+.fa-retweet:before {
+  content: "\f079";
+}
+.fa-shopping-cart:before {
+  content: "\f07a";
+}
+.fa-folder:before {
+  content: "\f07b";
+}
+.fa-folder-open:before {
+  content: "\f07c";
+}
+.fa-arrows-v:before {
+  content: "\f07d";
+}
+.fa-arrows-h:before {
+  content: "\f07e";
+}
+.fa-bar-chart-o:before,
+.fa-bar-chart:before {
+  content: "\f080";
+}
+.fa-twitter-square:before {
+  content: "\f081";
+}
+.fa-facebook-square:before {
+  content: "\f082";
+}
+.fa-camera-retro:before {
+  content: "\f083";
+}
+.fa-key:before {
+  content: "\f084";
+}
+.fa-gears:before,
+.fa-cogs:before {
+  content: "\f085";
+}
+.fa-comments:before {
+  content: "\f086";
+}
+.fa-thumbs-o-up:before {
+  content: "\f087";
+}
+.fa-thumbs-o-down:before {
+  content: "\f088";
+}
+.fa-star-half:before {
+  content: "\f089";
+}
+.fa-heart-o:before {
+  content: "\f08a";
+}
+.fa-sign-out:before {
+  content: "\f08b";
+}
+.fa-linkedin-square:before {
+  content: "\f08c";
+}
+.fa-thumb-tack:before {
+  content: "\f08d";
+}
+.fa-external-link:before {
+  content: "\f08e";
+}
+.fa-sign-in:before {
+  content: "\f090";
+}
+.fa-trophy:before {
+  content: "\f091";
+}
+.fa-github-square:before {
+  content: "\f092";
+}
+.fa-upload:before {
+  content: "\f093";
+}
+.fa-lemon-o:before {
+  content: "\f094";
+}
+.fa-phone:before {
+  content: "\f095";
+}
+.fa-square-o:before {
+  content: "\f096";
+}
+.fa-bookmark-o:before {
+  content: "\f097";
+}
+.fa-phone-square:before {
+  content: "\f098";
+}
+.fa-twitter:before {
+  content: "\f099";
+}
+.fa-facebook-f:before,
+.fa-facebook:before {
+  content: "\f09a";
+}
+.fa-github:before {
+  content: "\f09b";
+}
+.fa-unlock:before {
+  content: "\f09c";
+}
+.fa-credit-card:before {
+  content: "\f09d";
+}
+.fa-rss:before {
+  content: "\f09e";
+}
+.fa-hdd-o:before {
+  content: "\f0a0";
+}
+.fa-bullhorn:before {
+  content: "\f0a1";
+}
+.fa-bell:before {
+  content: "\f0f3";
+}
+.fa-certificate:before {
+  content: "\f0a3";
+}
+.fa-hand-o-right:before {
+  content: "\f0a4";
+}
+.fa-hand-o-left:before {
+  content: "\f0a5";
+}
+.fa-hand-o-up:before {
+  content: "\f0a6";
+}
+.fa-hand-o-down:before {
+  content: "\f0a7";
+}
+.fa-arrow-circle-left:before {
+  content: "\f0a8";
+}
+.fa-arrow-circle-right:before {
+  content: "\f0a9";
+}
+.fa-arrow-circle-up:before {
+  content: "\f0aa";
+}
+.fa-arrow-circle-down:before {
+  content: "\f0ab";
+}
+.fa-globe:before {
+  content: "\f0ac";
+}
+.fa-wrench:before {
+  content: "\f0ad";
+}
+.fa-tasks:before {
+  content: "\f0ae";
+}
+.fa-filter:before {
+  content: "\f0b0";
+}
+.fa-briefcase:before {
+  content: "\f0b1";
+}
+.fa-arrows-alt:before {
+  content: "\f0b2";
+}
+.fa-group:before,
+.fa-users:before {
+  content: "\f0c0";
+}
+.fa-chain:before,
+.fa-link:before {
+  content: "\f0c1";
+}
+.fa-cloud:before {
+  content: "\f0c2";
+}
+.fa-flask:before {
+  content: "\f0c3";
+}
+.fa-cut:before,
+.fa-scissors:before {
+  content: "\f0c4";
+}
+.fa-copy:before,
+.fa-files-o:before {
+  content: "\f0c5";
+}
+.fa-paperclip:before {
+  content: "\f0c6";
+}
+.fa-save:before,
+.fa-floppy-o:before {
+  content: "\f0c7";
+}
+.fa-square:before {
+  content: "\f0c8";
+}
+.fa-navicon:before,
+.fa-reorder:before,
+.fa-bars:before {
+  content: "\f0c9";
+}
+.fa-list-ul:before {
+  content: "\f0ca";
+}
+.fa-list-ol:before {
+  content: "\f0cb";
+}
+.fa-strikethrough:before {
+  content: "\f0cc";
+}
+.fa-underline:before {
+  content: "\f0cd";
+}
+.fa-table:before {
+  content: "\f0ce";
+}
+.fa-magic:before {
+  content: "\f0d0";
+}
+.fa-truck:before {
+  content: "\f0d1";
+}
+.fa-pinterest:before {
+  content: "\f0d2";
+}
+.fa-pinterest-square:before {
+  content: "\f0d3";
+}
+.fa-google-plus-square:before {
+  content: "\f0d4";
+}
+.fa-google-plus:before {
+  content: "\f0d5";
+}
+.fa-money:before {
+  content: "\f0d6";
+}
+.fa-caret-down:before {
+  content: "\f0d7";
+}
+.fa-caret-up:before {
+  content: "\f0d8";
+}
+.fa-caret-left:before {
+  content: "\f0d9";
+}
+.fa-caret-right:before {
+  content: "\f0da";
+}
+.fa-columns:before {
+  content: "\f0db";
+}
+.fa-unsorted:before,
+.fa-sort:before {
+  content: "\f0dc";
+}
+.fa-sort-down:before,
+.fa-sort-desc:before {
+  content: "\f0dd";
+}
+.fa-sort-up:before,
+.fa-sort-asc:before {
+  content: "\f0de";
+}
+.fa-envelope:before {
+  content: "\f0e0";
+}
+.fa-linkedin:before {
+  content: "\f0e1";
+}
+.fa-rotate-left:before,
+.fa-undo:before {
+  content: "\f0e2";
+}
+.fa-legal:before,
+.fa-gavel:before {
+  content: "\f0e3";
+}
+.fa-dashboard:before,
+.fa-tachometer:before {
+  content: "\f0e4";
+}
+.fa-comment-o:before {
+  content: "\f0e5";
+}
+.fa-comments-o:before {
+  content: "\f0e6";
+}
+.fa-flash:before,
+.fa-bolt:before {
+  content: "\f0e7";
+}
+.fa-sitemap:before {
+  content: "\f0e8";
+}
+.fa-umbrella:before {
+  content: "\f0e9";
+}
+.fa-paste:before,
+.fa-clipboard:before {
+  content: "\f0ea";
+}
+.fa-lightbulb-o:before {
+  content: "\f0eb";
+}
+.fa-exchange:before {
+  content: "\f0ec";
+}
+.fa-cloud-download:before {
+  content: "\f0ed";
+}
+.fa-cloud-upload:before {
+  content: "\f0ee";
+}
+.fa-user-md:before {
+  content: "\f0f0";
+}
+.fa-stethoscope:before {
+  content: "\f0f1";
+}
+.fa-suitcase:before {
+  content: "\f0f2";
+}
+.fa-bell-o:before {
+  content: "\f0a2";
+}
+.fa-coffee:before {
+  content: "\f0f4";
+}
+.fa-cutlery:before {
+  content: "\f0f5";
+}
+.fa-file-text-o:before {
+  content: "\f0f6";
+}
+.fa-building-o:before {
+  content: "\f0f7";
+}
+.fa-hospital-o:before {
+  content: "\f0f8";
+}
+.fa-ambulance:before {
+  content: "\f0f9";
+}
+.fa-medkit:before {
+  content: "\f0fa";
+}
+.fa-fighter-jet:before {
+  content: "\f0fb";
+}
+.fa-beer:before {
+  content: "\f0fc";
+}
+.fa-h-square:before {
+  content: "\f0fd";
+}
+.fa-plus-square:before {
+  content: "\f0fe";
+}
+.fa-angle-double-left:before {
+  content: "\f100";
+}
+.fa-angle-double-right:before {
+  content: "\f101";
+}
+.fa-angle-double-up:before {
+  content: "\f102";
+}
+.fa-angle-double-down:before {
+  content: "\f103";
+}
+.fa-angle-left:before {
+  content: "\f104";
+}
+.fa-angle-right:before {
+  content: "\f105";
+}
+.fa-angle-up:before {
+  content: "\f106";
+}
+.fa-angle-down:before {
+  content: "\f107";
+}
+.fa-desktop:before {
+  content: "\f108";
+}
+.fa-laptop:before {
+  content: "\f109";
+}
+.fa-tablet:before {
+  content: "\f10a";
+}
+.fa-mobile-phone:before,
+.fa-mobile:before {
+  content: "\f10b";
+}
+.fa-circle-o:before {
+  content: "\f10c";
+}
+.fa-quote-left:before {
+  content: "\f10d";
+}
+.fa-quote-right:before {
+  content: "\f10e";
+}
+.fa-spinner:before {
+  content: "\f110";
+}
+.fa-circle:before {
+  content: "\f111";
+}
+.fa-mail-reply:before,
+.fa-reply:before {
+  content: "\f112";
+}
+.fa-github-alt:before {
+  content: "\f113";
+}
+.fa-folder-o:before {
+  content: "\f114";
+}
+.fa-folder-open-o:before {
+  content: "\f115";
+}
+.fa-smile-o:before {
+  content: "\f118";
+}
+.fa-frown-o:before {
+  content: "\f119";
+}
+.fa-meh-o:before {
+  content: "\f11a";
+}
+.fa-gamepad:before {
+  content: "\f11b";
+}
+.fa-keyboard-o:before {
+  content: "\f11c";
+}
+.fa-flag-o:before {
+  content: "\f11d";
+}
+.fa-flag-checkered:before {
+  content: "\f11e";
+}
+.fa-terminal:before {
+  content: "\f120";
+}
+.fa-code:before {
+  content: "\f121";
+}
+.fa-mail-reply-all:before,
+.fa-reply-all:before {
+  content: "\f122";
+}
+.fa-star-half-empty:before,
+.fa-star-half-full:before,
+.fa-star-half-o:before {
+  content: "\f123";
+}
+.fa-location-arrow:before {
+  content: "\f124";
+}
+.fa-crop:before {
+  content: "\f125";
+}
+.fa-code-fork:before {
+  content: "\f126";
+}
+.fa-unlink:before,
+.fa-chain-broken:before {
+  content: "\f127";
+}
+.fa-question:before {
+  content: "\f128";
+}
+.fa-info:before {
+  content: "\f129";
+}
+.fa-exclamation:before {
+  content: "\f12a";
+}
+.fa-superscript:before {
+  content: "\f12b";
+}
+.fa-subscript:before {
+  content: "\f12c";
+}
+.fa-eraser:before {
+  content: "\f12d";
+}
+.fa-puzzle-piece:before {
+  content: "\f12e";
+}
+.fa-microphone:before {
+  content: "\f130";
+}
+.fa-microphone-slash:before {
+  content: "\f131";
+}
+.fa-shield:before {
+  content: "\f132";
+}
+.fa-calendar-o:before {
+  content: "\f133";
+}
+.fa-fire-extinguisher:before {
+  content: "\f134";
+}
+.fa-rocket:before {
+  content: "\f135";
+}
+.fa-maxcdn:before {
+  content: "\f136";
+}
+.fa-chevron-circle-left:before {
+  content: "\f137";
+}
+.fa-chevron-circle-right:before {
+  content: "\f138";
+}
+.fa-chevron-circle-up:before {
+  content: "\f139";
+}
+.fa-chevron-circle-down:before {
+  content: "\f13a";
+}
+.fa-html5:before {
+  content: "\f13b";
+}
+.fa-css3:before {
+  content: "\f13c";
+}
+.fa-anchor:before {
+  content: "\f13d";
+}
+.fa-unlock-alt:before {
+  content: "\f13e";
+}
+.fa-bullseye:before {
+  content: "\f140";
+}
+.fa-ellipsis-h:before {
+  content: "\f141";
+}
+.fa-ellipsis-v:before {
+  content: "\f142";
+}
+.fa-rss-square:before {
+  content: "\f143";
+}
+.fa-play-circle:before {
+  content: "\f144";
+}
+.fa-ticket:before {
+  content: "\f145";
+}
+.fa-minus-square:before {
+  content: "\f146";
+}
+.fa-minus-square-o:before {
+  content: "\f147";
+}
+.fa-level-up:before {
+  content: "\f148";
+}
+.fa-level-down:before {
+  content: "\f149";
+}
+.fa-check-square:before {
+  content: "\f14a";
+}
+.fa-pencil-square:before {
+  content: "\f14b";
+}
+.fa-external-link-square:before {
+  content: "\f14c";
+}
+.fa-share-square:before {
+  content: "\f14d";
+}
+.fa-compass:before {
+  content: "\f14e";
+}
+.fa-toggle-down:before,
+.fa-caret-square-o-down:before {
+  content: "\f150";
+}
+.fa-toggle-up:before,
+.fa-caret-square-o-up:before {
+  content: "\f151";
+}
+.fa-toggle-right:before,
+.fa-caret-square-o-right:before {
+  content: "\f152";
+}
+.fa-euro:before,
+.fa-eur:before {
+  content: "\f153";
+}
+.fa-gbp:before {
+  content: "\f154";
+}
+.fa-dollar:before,
+.fa-usd:before {
+  content: "\f155";
+}
+.fa-rupee:before,
+.fa-inr:before {
+  content: "\f156";
+}
+.fa-cny:before,
+.fa-rmb:before,
+.fa-yen:before,
+.fa-jpy:before {
+  content: "\f157";
+}
+.fa-ruble:before,
+.fa-rouble:before,
+.fa-rub:before {
+  content: "\f158";
+}
+.fa-won:before,
+.fa-krw:before {
+  content: "\f159";
+}
+.fa-bitcoin:before,
+.fa-btc:before {
+  content: "\f15a";
+}
+.fa-file:before {
+  content: "\f15b";
+}
+.fa-file-text:before {
+  content: "\f15c";
+}
+.fa-sort-alpha-asc:before {
+  content: "\f15d";
+}
+.fa-sort-alpha-desc:before {
+  content: "\f15e";
+}
+.fa-sort-amount-asc:before {
+  content: "\f160";
+}
+.fa-sort-amount-desc:before {
+  content: "\f161";
+}
+.fa-sort-numeric-asc:before {
+  content: "\f162";
+}
+.fa-sort-numeric-desc:before {
+  content: "\f163";
+}
+.fa-thumbs-up:before {
+  content: "\f164";
+}
+.fa-thumbs-down:before {
+  content: "\f165";
+}
+.fa-youtube-square:before {
+  content: "\f166";
+}
+.fa-youtube:before {
+  content: "\f167";
+}
+.fa-xing:before {
+  content: "\f168";
+}
+.fa-xing-square:before {
+  content: "\f169";
+}
+.fa-youtube-play:before {
+  content: "\f16a";
+}
+.fa-dropbox:before {
+  content: "\f16b";
+}
+.fa-stack-overflow:before {
+  content: "\f16c";
+}
+.fa-instagram:before {
+  content: "\f16d";
+}
+.fa-flickr:before {
+  content: "\f16e";
+}
+.fa-adn:before {
+  content: "\f170";
+}
+.fa-bitbucket:before {
+  content: "\f171";
+}
+.fa-bitbucket-square:before {
+  content: "\f172";
+}
+.fa-tumblr:before {
+  content: "\f173";
+}
+.fa-tumblr-square:before {
+  content: "\f174";
+}
+.fa-long-arrow-down:before {
+  content: "\f175";
+}
+.fa-long-arrow-up:before {
+  content: "\f176";
+}
+.fa-long-arrow-left:before {
+  content: "\f177";
+}
+.fa-long-arrow-right:before {
+  content: "\f178";
+}
+.fa-apple:before {
+  content: "\f179";
+}
+.fa-windows:before {
+  content: "\f17a";
+}
+.fa-android:before {
+  content: "\f17b";
+}
+.fa-linux:before {
+  content: "\f17c";
+}
+.fa-dribbble:before {
+  content: "\f17d";
+}
+.fa-skype:before {
+  content: "\f17e";
+}
+.fa-foursquare:before {
+  content: "\f180";
+}
+.fa-trello:before {
+  content: "\f181";
+}
+.fa-female:before {
+  content: "\f182";
+}
+.fa-male:before {
+  content: "\f183";
+}
+.fa-gittip:before,
+.fa-gratipay:before {
+  content: "\f184";
+}
+.fa-sun-o:before {
+  content: "\f185";
+}
+.fa-moon-o:before {
+  content: "\f186";
+}
+.fa-archive:before {
+  content: "\f187";
+}
+.fa-bug:before {
+  content: "\f188";
+}
+.fa-vk:before {
+  content: "\f189";
+}
+.fa-weibo:before {
+  content: "\f18a";
+}
+.fa-renren:before {
+  content: "\f18b";
+}
+.fa-pagelines:before {
+  content: "\f18c";
+}
+.fa-stack-exchange:before {
+  content: "\f18d";
+}
+.fa-arrow-circle-o-right:before {
+  content: "\f18e";
+}
+.fa-arrow-circle-o-left:before {
+  content: "\f190";
+}
+.fa-toggle-left:before,
+.fa-caret-square-o-left:before {
+  content: "\f191";
+}
+.fa-dot-circle-o:before {
+  content: "\f192";
+}
+.fa-wheelchair:before {
+  content: "\f193";
+}
+.fa-vimeo-square:before {
+  content: "\f194";
+}
+.fa-turkish-lira:before,
+.fa-try:before {
+  content: "\f195";
+}
+.fa-plus-square-o:before {
+  content: "\f196";
+}
+.fa-space-shuttle:before {
+  content: "\f197";
+}
+.fa-slack:before {
+  content: "\f198";
+}
+.fa-envelope-square:before {
+  content: "\f199";
+}
+.fa-wordpress:before {
+  content: "\f19a";
+}
+.fa-openid:before {
+  content: "\f19b";
+}
+.fa-institution:before,
+.fa-bank:before,
+.fa-university:before {
+  content: "\f19c";
+}
+.fa-mortar-board:before,
+.fa-graduation-cap:before {
+  content: "\f19d";
+}
+.fa-yahoo:before {
+  content: "\f19e";
+}
+.fa-google:before {
+  content: "\f1a0";
+}
+.fa-reddit:before {
+  content: "\f1a1";
+}
+.fa-reddit-square:before {
+  content: "\f1a2";
+}
+.fa-stumbleupon-circle:before {
+  content: "\f1a3";
+}
+.fa-stumbleupon:before {
+  content: "\f1a4";
+}
+.fa-delicious:before {
+  content: "\f1a5";
+}
+.fa-digg:before {
+  content: "\f1a6";
+}
+.fa-pied-piper:before {
+  content: "\f1a7";
+}
+.fa-pied-piper-alt:before {
+  content: "\f1a8";
+}
+.fa-drupal:before {
+  content: "\f1a9";
+}
+.fa-joomla:before {
+  content: "\f1aa";
+}
+.fa-language:before {
+  content: "\f1ab";
+}
+.fa-fax:before {
+  content: "\f1ac";
+}
+.fa-building:before {
+  content: "\f1ad";
+}
+.fa-child:before {
+  content: "\f1ae";
+}
+.fa-paw:before {
+  content: "\f1b0";
+}
+.fa-spoon:before {
+  content: "\f1b1";
+}
+.fa-cube:before {
+  content: "\f1b2";
+}
+.fa-cubes:before {
+  content: "\f1b3";
+}
+.fa-behance:before {
+  content: "\f1b4";
+}
+.fa-behance-square:before {
+  content: "\f1b5";
+}
+.fa-steam:before {
+  content: "\f1b6";
+}
+.fa-steam-square:before {
+  content: "\f1b7";
+}
+.fa-recycle:before {
+  content: "\f1b8";
+}
+.fa-automobile:before,
+.fa-car:before {
+  content: "\f1b9";
+}
+.fa-cab:before,
+.fa-taxi:before {
+  content: "\f1ba";
+}
+.fa-tree:before {
+  content: "\f1bb";
+}
+.fa-spotify:before {
+  content: "\f1bc";
+}
+.fa-deviantart:before {
+  content: "\f1bd";
+}
+.fa-soundcloud:before {
+  content: "\f1be";
+}
+.fa-database:before {
+  content: "\f1c0";
+}
+.fa-file-pdf-o:before {
+  content: "\f1c1";
+}
+.fa-file-word-o:before {
+  content: "\f1c2";
+}
+.fa-file-excel-o:before {
+  content: "\f1c3";
+}
+.fa-file-powerpoint-o:before {
+  content: "\f1c4";
+}
+.fa-file-photo-o:before,
+.fa-file-picture-o:before,
+.fa-file-image-o:before {
+  content: "\f1c5";
+}
+.fa-file-zip-o:before,
+.fa-file-archive-o:before {
+  content: "\f1c6";
+}
+.fa-file-sound-o:before,
+.fa-file-audio-o:before {
+  content: "\f1c7";
+}
+.fa-file-movie-o:before,
+.fa-file-video-o:before {
+  content: "\f1c8";
+}
+.fa-file-code-o:before {
+  content: "\f1c9";
+}
+.fa-vine:before {
+  content: "\f1ca";
+}
+.fa-codepen:before {
+  content: "\f1cb";
+}
+.fa-jsfiddle:before {
+  content: "\f1cc";
+}
+.fa-life-bouy:before,
+.fa-life-buoy:before,
+.fa-life-saver:before,
+.fa-support:before,
+.fa-life-ring:before {
+  content: "\f1cd";
+}
+.fa-circle-o-notch:before {
+  content: "\f1ce";
+}
+.fa-ra:before,
+.fa-rebel:before {
+  content: "\f1d0";
+}
+.fa-ge:before,
+.fa-empire:before {
+  content: "\f1d1";
+}
+.fa-git-square:before {
+  content: "\f1d2";
+}
+.fa-git:before {
+  content: "\f1d3";
+}
+.fa-hacker-news:before {
+  content: "\f1d4";
+}
+.fa-tencent-weibo:before {
+  content: "\f1d5";
+}
+.fa-qq:before {
+  content: "\f1d6";
+}
+.fa-wechat:before,
+.fa-weixin:before {
+  content: "\f1d7";
+}
+.fa-send:before,
+.fa-paper-plane:before {
+  content: "\f1d8";
+}
+.fa-send-o:before,
+.fa-paper-plane-o:before {
+  content: "\f1d9";
+}
+.fa-history:before {
+  content: "\f1da";
+}
+.fa-genderless:before,
+.fa-circle-thin:before {
+  content: "\f1db";
+}
+.fa-header:before {
+  content: "\f1dc";
+}
+.fa-paragraph:before {
+  content: "\f1dd";
+}
+.fa-sliders:before {
+  content: "\f1de";
+}
+.fa-share-alt:before {
+  content: "\f1e0";
+}
+.fa-share-alt-square:before {
+  content: "\f1e1";
+}
+.fa-bomb:before {
+  content: "\f1e2";
+}
+.fa-soccer-ball-o:before,
+.fa-futbol-o:before {
+  content: "\f1e3";
+}
+.fa-tty:before {
+  content: "\f1e4";
+}
+.fa-binoculars:before {
+  content: "\f1e5";
+}
+.fa-plug:before {
+  content: "\f1e6";
+}
+.fa-slideshare:before {
+  content: "\f1e7";
+}
+.fa-twitch:before {
+  content: "\f1e8";
+}
+.fa-yelp:before {
+  content: "\f1e9";
+}
+.fa-newspaper-o:before {
+  content: "\f1ea";
+}
+.fa-wifi:before {
+  content: "\f1eb";
+}
+.fa-calculator:before {
+  content: "\f1ec";
+}
+.fa-paypal:before {
+  content: "\f1ed";
+}
+.fa-google-wallet:before {
+  content: "\f1ee";
+}
+.fa-cc-visa:before {
+  content: "\f1f0";
+}
+.fa-cc-mastercard:before {
+  content: "\f1f1";
+}
+.fa-cc-discover:before {
+  content: "\f1f2";
+}
+.fa-cc-amex:before {
+  content: "\f1f3";
+}
+.fa-cc-paypal:before {
+  content: "\f1f4";
+}
+.fa-cc-stripe:before {
+  content: "\f1f5";
+}
+.fa-bell-slash:before {
+  content: "\f1f6";
+}
+.fa-bell-slash-o:before {
+  content: "\f1f7";
+}
+.fa-trash:before {
+  content: "\f1f8";
+}
+.fa-copyright:before {
+  content: "\f1f9";
+}
+.fa-at:before {
+  content: "\f1fa";
+}
+.fa-eyedropper:before {
+  content: "\f1fb";
+}
+.fa-paint-brush:before {
+  content: "\f1fc";
+}
+.fa-birthday-cake:before {
+  content: "\f1fd";
+}
+.fa-area-chart:before {
+  content: "\f1fe";
+}
+.fa-pie-chart:before {
+  content: "\f200";
+}
+.fa-line-chart:before {
+  content: "\f201";
+}
+.fa-lastfm:before {
+  content: "\f202";
+}
+.fa-lastfm-square:before {
+  content: "\f203";
+}
+.fa-toggle-off:before {
+  content: "\f204";
+}
+.fa-toggle-on:before {
+  content: "\f205";
+}
+.fa-bicycle:before {
+  content: "\f206";
+}
+.fa-bus:before {
+  content: "\f207";
+}
+.fa-ioxhost:before {
+  content: "\f208";
+}
+.fa-angellist:before {
+  content: "\f209";
+}
+.fa-cc:before {
+  content: "\f20a";
+}
+.fa-shekel:before,
+.fa-sheqel:before,
+.fa-ils:before {
+  content: "\f20b";
+}
+.fa-meanpath:before {
+  content: "\f20c";
+}
+.fa-buysellads:before {
+  content: "\f20d";
+}
+.fa-connectdevelop:before {
+  content: "\f20e";
+}
+.fa-dashcube:before {
+  content: "\f210";
+}
+.fa-forumbee:before {
+  content: "\f211";
+}
+.fa-leanpub:before {
+  content: "\f212";
+}
+.fa-sellsy:before {
+  content: "\f213";
+}
+.fa-shirtsinbulk:before {
+  content: "\f214";
+}
+.fa-simplybuilt:before {
+  content: "\f215";
+}
+.fa-skyatlas:before {
+  content: "\f216";
+}
+.fa-cart-plus:before {
+  content: "\f217";
+}
+.fa-cart-arrow-down:before {
+  content: "\f218";
+}
+.fa-diamond:before {
+  content: "\f219";
+}
+.fa-ship:before {
+  content: "\f21a";
+}
+.fa-user-secret:before {
+  content: "\f21b";
+}
+.fa-motorcycle:before {
+  content: "\f21c";
+}
+.fa-street-view:before {
+  content: "\f21d";
+}
+.fa-heartbeat:before {
+  content: "\f21e";
+}
+.fa-venus:before {
+  content: "\f221";
+}
+.fa-mars:before {
+  content: "\f222";
+}
+.fa-mercury:before {
+  content: "\f223";
+}
+.fa-transgender:before {
+  content: "\f224";
+}
+.fa-transgender-alt:before {
+  content: "\f225";
+}
+.fa-venus-double:before {
+  content: "\f226";
+}
+.fa-mars-double:before {
+  content: "\f227";
+}
+.fa-venus-mars:before {
+  content: "\f228";
+}
+.fa-mars-stroke:before {
+  content: "\f229";
+}
+.fa-mars-stroke-v:before {
+  content: "\f22a";
+}
+.fa-mars-stroke-h:before {
+  content: "\f22b";
+}
+.fa-neuter:before {
+  content: "\f22c";
+}
+.fa-facebook-official:before {
+  content: "\f230";
+}
+.fa-pinterest-p:before {
+  content: "\f231";
+}
+.fa-whatsapp:before {
+  content: "\f232";
+}
+.fa-server:before {
+  content: "\f233";
+}
+.fa-user-plus:before {
+  content: "\f234";
+}
+.fa-user-times:before {
+  content: "\f235";
+}
+.fa-hotel:before,
+.fa-bed:before {
+  content: "\f236";
+}
+.fa-viacoin:before {
+  content: "\f237";
+}
+.fa-train:before {
+  content: "\f238";
+}
+.fa-subway:before {
+  content: "\f239";
+}
+.fa-medium:before {
+  content: "\f23a";
+}
diff --git a/dicoogle/src/main/resources/webapp/css/font-awesome.min.css b/dicoogle/src/main/resources/webapp/css/font-awesome.min.css
new file mode 100644
index 0000000..24fcc04
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ *  Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:norma [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/css/fonts-google.css b/dicoogle/src/main/resources/webapp/css/fonts-google.css
new file mode 100644
index 0000000..6e80822
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/fonts-google.css
@@ -0,0 +1,6 @@
+ at font-face {
+  font-family: 'Lato';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Lato Regular'), local('Lato-Regular'), url(http://fonts.gstatic.com/s/lato/v11/v0SdcGFAl2aezM9Vq_aFTQ.ttf) format('truetype');
+}
diff --git a/dicoogle/src/main/resources/webapp/css/images/ui-bg_flat_75_ffffff_40x100.png b/dicoogle/src/main/resources/webapp/css/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 0000000..ac8b229
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/css/images/ui-bg_flat_75_ffffff_40x100.png differ
diff --git a/dicoogle/src/main/resources/webapp/css/jquery-ui.css b/dicoogle/src/main/resources/webapp/css/jquery-ui.css
new file mode 100644
index 0000000..1c22746
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/jquery-ui.css
@@ -0,0 +1,1225 @@
+/*! jQuery UI - v1.11.4 - 2015-03-11
+* http://jqueryui.com
+* Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDe [...]
+* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+	display: none;
+}
+.ui-helper-hidden-accessible {
+	border: 0;
+	clip: rect(0 0 0 0);
+	height: 1px;
+	margin: -1px;
+	overflow: hidden;
+	padding: 0;
+	position: absolute;
+	width: 1px;
+}
+.ui-helper-reset {
+	margin: 0;
+	padding: 0;
+	border: 0;
+	outline: 0;
+	line-height: 1.3;
+	text-decoration: none;
+	font-size: 100%;
+	list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+	content: "";
+	display: table;
+	border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+	clear: both;
+}
+.ui-helper-clearfix {
+	min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+	width: 100%;
+	height: 100%;
+	top: 0;
+	left: 0;
+	position: absolute;
+	opacity: 0;
+	filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+	z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+	cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	display: block;
+	text-indent: -99999px;
+	overflow: hidden;
+	background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+	position: fixed;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+}
+.ui-accordion .ui-accordion-header {
+	display: block;
+	cursor: pointer;
+	position: relative;
+	margin: 2px 0 0 0;
+	padding: .5em .5em .5em .7em;
+	min-height: 0; /* support: IE7 */
+	font-size: 100%;
+}
+.ui-accordion .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+	padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+	position: absolute;
+	left: .5em;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+	padding: 1em 2.2em;
+	border-top: 0;
+	overflow: auto;
+}
+.ui-autocomplete {
+	position: absolute;
+	top: 0;
+	left: 0;
+	cursor: default;
+}
+.ui-button {
+	display: inline-block;
+	position: relative;
+	padding: 0;
+	line-height: normal;
+	margin-right: .1em;
+	cursor: pointer;
+	vertical-align: middle;
+	text-align: center;
+	overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+	text-decoration: none;
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+	width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+	width: 2.4em;
+}
+.ui-button-icons-only {
+	width: 3.4em;
+}
+button.ui-button-icons-only {
+	width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+	display: block;
+	line-height: normal;
+}
+.ui-button-text-only .ui-button-text {
+	padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+	padding: .4em;
+	text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+	padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+	padding-left: 2.1em;
+	padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+	padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+	position: absolute;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+	left: 50%;
+	margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+	left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+	right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+	margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+	margin-left: 0;
+	margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+	border: 0;
+	padding: 0;
+}
+.ui-datepicker {
+	width: 17em;
+	padding: .2em .2em 0;
+	display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+	position: relative;
+	padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+	position: absolute;
+	top: 2px;
+	width: 1.8em;
+	height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+	top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+	left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+	right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+	left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+	right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+	display: block;
+	position: absolute;
+	left: 50%;
+	margin-left: -8px;
+	top: 50%;
+	margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+	margin: 0 2.3em;
+	line-height: 1.8em;
+	text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+	font-size: 1em;
+	margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+	width: 45%;
+}
+.ui-datepicker table {
+	width: 100%;
+	font-size: .9em;
+	border-collapse: collapse;
+	margin: 0 0 .4em;
+}
+.ui-datepicker th {
+	padding: .7em .3em;
+	text-align: center;
+	font-weight: bold;
+	border: 0;
+}
+.ui-datepicker td {
+	border: 0;
+	padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+	display: block;
+	padding: .2em;
+	text-align: right;
+	text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+	background-image: none;
+	margin: .7em 0 0 0;
+	padding: 0 .2em;
+	border-left: 0;
+	border-right: 0;
+	border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+	float: right;
+	margin: .5em .2em .4em;
+	cursor: pointer;
+	padding: .2em .6em .3em .6em;
+	width: auto;
+	overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+	float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+	width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+	float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+	width: 95%;
+	margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+	width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+	width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+	width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+	border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+	clear: left;
+}
+.ui-datepicker-row-break {
+	clear: both;
+	width: 100%;
+	font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+	direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+	right: 2px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+	left: 2px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+	right: 1px;
+	left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+	left: 1px;
+	right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+	clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+	float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+	float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+	border-right-width: 0;
+	border-left-width: 1px;
+}
+.ui-dialog {
+	overflow: hidden;
+	position: absolute;
+	top: 0;
+	left: 0;
+	padding: .2em;
+	outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+	padding: .4em 1em;
+	position: relative;
+}
+.ui-dialog .ui-dialog-title {
+	float: left;
+	margin: .1em 0;
+	white-space: nowrap;
+	width: 90%;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+	position: absolute;
+	right: .3em;
+	top: 50%;
+	width: 20px;
+	margin: -10px 0 0 0;
+	padding: 1px;
+	height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+	position: relative;
+	border: 0;
+	padding: .5em 1em;
+	background: none;
+	overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+	text-align: left;
+	border-width: 1px 0 0 0;
+	background-image: none;
+	margin-top: .5em;
+	padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+	float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+	margin: .5em .4em .5em 0;
+	cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+	width: 12px;
+	height: 12px;
+	right: -5px;
+	bottom: -5px;
+	background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+	cursor: move;
+}
+.ui-draggable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-menu {
+	list-style: none;
+	padding: 0;
+	margin: 0;
+	display: block;
+	outline: none;
+}
+.ui-menu .ui-menu {
+	position: absolute;
+}
+.ui-menu .ui-menu-item {
+	position: relative;
+	margin: 0;
+	padding: 3px 1em 3px .4em;
+	cursor: pointer;
+	min-height: 0; /* support: IE7 */
+	/* support: IE10, see #8844 */
+	list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+}
+.ui-menu .ui-menu-divider {
+	margin: 5px 0;
+	height: 0;
+	font-size: 0;
+	line-height: 0;
+	border-width: 1px 0 0 0;
+}
+.ui-menu .ui-state-focus,
+.ui-menu .ui-state-active {
+	margin: -1px;
+}
+
+/* icon support */
+.ui-menu-icons {
+	position: relative;
+}
+.ui-menu-icons .ui-menu-item {
+	padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: .2em;
+	margin: auto 0;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+	left: auto;
+	right: 0;
+}
+.ui-progressbar {
+	height: 2em;
+	text-align: left;
+	overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+	margin: -1px;
+	height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+	background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmo [...]
+	height: 100%;
+	filter: alpha(opacity=25); /* support: IE8 */
+	opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+	background-image: none;
+}
+.ui-resizable {
+	position: relative;
+}
+.ui-resizable-handle {
+	position: absolute;
+	font-size: 0.1px;
+	display: block;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+	display: none;
+}
+.ui-resizable-n {
+	cursor: n-resize;
+	height: 7px;
+	width: 100%;
+	top: -5px;
+	left: 0;
+}
+.ui-resizable-s {
+	cursor: s-resize;
+	height: 7px;
+	width: 100%;
+	bottom: -5px;
+	left: 0;
+}
+.ui-resizable-e {
+	cursor: e-resize;
+	width: 7px;
+	right: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-w {
+	cursor: w-resize;
+	width: 7px;
+	left: -5px;
+	top: 0;
+	height: 100%;
+}
+.ui-resizable-se {
+	cursor: se-resize;
+	width: 12px;
+	height: 12px;
+	right: 1px;
+	bottom: 1px;
+}
+.ui-resizable-sw {
+	cursor: sw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	bottom: -5px;
+}
+.ui-resizable-nw {
+	cursor: nw-resize;
+	width: 9px;
+	height: 9px;
+	left: -5px;
+	top: -5px;
+}
+.ui-resizable-ne {
+	cursor: ne-resize;
+	width: 9px;
+	height: 9px;
+	right: -5px;
+	top: -5px;
+}
+.ui-selectable {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-selectable-helper {
+	position: absolute;
+	z-index: 100;
+	border: 1px dotted black;
+}
+.ui-selectmenu-menu {
+	padding: 0;
+	margin: 0;
+	position: absolute;
+	top: 0;
+	left: 0;
+	display: none;
+}
+.ui-selectmenu-menu .ui-menu {
+	overflow: auto;
+	/* Support: IE7 */
+	overflow-x: hidden;
+	padding-bottom: 1px;
+}
+.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
+	font-size: 1em;
+	font-weight: bold;
+	line-height: 1.5;
+	padding: 2px 0.4em;
+	margin: 0.5em 0 0 0;
+	height: auto;
+	border: 0;
+}
+.ui-selectmenu-open {
+	display: block;
+}
+.ui-selectmenu-button {
+	display: inline-block;
+	overflow: hidden;
+	position: relative;
+	text-decoration: none;
+	cursor: pointer;
+}
+.ui-selectmenu-button span.ui-icon {
+	right: 0.5em;
+	left: auto;
+	margin-top: -8px;
+	position: absolute;
+	top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+	text-align: left;
+	padding: 0.4em 2.1em 0.4em 1em;
+	display: block;
+	line-height: 1.4;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}
+.ui-slider {
+	position: relative;
+	text-align: left;
+}
+.ui-slider .ui-slider-handle {
+	position: absolute;
+	z-index: 2;
+	width: 1.2em;
+	height: 1.2em;
+	cursor: default;
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-slider .ui-slider-range {
+	position: absolute;
+	z-index: 1;
+	font-size: .7em;
+	display: block;
+	border: 0;
+	background-position: 0 0;
+}
+
+/* support: IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+	filter: inherit;
+}
+
+.ui-slider-horizontal {
+	height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+	top: -.3em;
+	margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+	top: 0;
+	height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+	left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+	right: 0;
+}
+
+.ui-slider-vertical {
+	width: .8em;
+	height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+	left: -.3em;
+	margin-left: 0;
+	margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+	left: 0;
+	width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+	bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+	top: 0;
+}
+.ui-sortable-handle {
+	-ms-touch-action: none;
+	touch-action: none;
+}
+.ui-spinner {
+	position: relative;
+	display: inline-block;
+	overflow: hidden;
+	padding: 0;
+	vertical-align: middle;
+}
+.ui-spinner-input {
+	border: none;
+	background: none;
+	color: inherit;
+	padding: 0;
+	margin: .2em 0;
+	vertical-align: middle;
+	margin-left: .4em;
+	margin-right: 22px;
+}
+.ui-spinner-button {
+	width: 16px;
+	height: 50%;
+	font-size: .5em;
+	padding: 0;
+	margin: 0;
+	text-align: center;
+	position: absolute;
+	cursor: default;
+	display: block;
+	overflow: hidden;
+	right: 0;
+}
+/* more specificity required here to override default borders */
+.ui-spinner a.ui-spinner-button {
+	border-top: none;
+	border-bottom: none;
+	border-right: none;
+}
+/* vertically center icon */
+.ui-spinner .ui-icon {
+	position: absolute;
+	margin-top: -8px;
+	top: 50%;
+	left: 0;
+}
+.ui-spinner-up {
+	top: 0;
+}
+.ui-spinner-down {
+	bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+	/* need to fix icons sprite */
+	background-position: -65px -16px;
+}
+.ui-tabs {
+	position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+	padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+	margin: 0;
+	padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+	list-style: none;
+	float: left;
+	position: relative;
+	top: 0;
+	margin: 1px .2em 0 0;
+	border-bottom-width: 0;
+	padding: 0;
+	white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+	float: left;
+	padding: .5em 1em;
+	text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+	margin-bottom: -1px;
+	padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+	cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+	cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+	display: block;
+	border-width: 0;
+	padding: 1em 1.4em;
+	background: none;
+}
+.ui-tooltip {
+	padding: 8px;
+	position: absolute;
+	z-index: 9999;
+	max-width: 300px;
+	-webkit-box-shadow: 0 0 5px #aaa;
+	box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+	border-width: 2px;
+}
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+	font-family: Verdana,Arial,sans-serif;
+	font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+	font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+	font-family: Verdana,Arial,sans-serif;
+	font-size: 1em;
+}
+.ui-widget-content {
+	border: 1px solid #aaaaaa;
+	background: #ffffff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;
+	color: #222222;
+}
+.ui-widget-content a {
+	color: #222222;
+}
+.ui-widget-header {
+	border: 1px solid #aaaaaa;
+	background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+	color: #222222;
+	font-weight: bold;
+}
+.ui-widget-header a {
+	color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+	border: 1px solid #d3d3d3;
+	background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #555555;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+	color: #555555;
+	text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+	border: 1px solid #999999;
+	background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #212121;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited {
+	color: #212121;
+	text-decoration: none;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+	border: 1px solid #aaaaaa;
+	background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+	font-weight: normal;
+	color: #212121;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+	color: #212121;
+	text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+	border: 1px solid #fcefa1;
+	background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
+	color: #363636;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+	color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+	border: 1px solid #cd0a0a;
+	background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
+	color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+	color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+	color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+	font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+	opacity: .7;
+	filter:Alpha(Opacity=70); /* support: IE8 */
+	font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+	opacity: .35;
+	filter:Alpha(Opacity=35); /* support: IE8 */
+	background-image: none;
+}
+.ui-state-disabled .ui-icon {
+	filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+	width: 16px;
+	height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+	background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-default .ui-icon {
+	background-image: url("images/ui-icons_888888_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-active .ui-icon {
+	background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon {
+	background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+	background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+	border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+	border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+	border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+	border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+	background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
+	opacity: .3;
+	filter: Alpha(Opacity=30); /* support: IE8 */
+}
+.ui-widget-shadow {
+	margin: -8px 0 0 -8px;
+	padding: 8px;
+	background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
+	opacity: .3;
+	filter: Alpha(Opacity=30); /* support: IE8 */
+	border-radius: 8px;
+}
diff --git a/dicoogle/src/main/resources/webapp/css/loaders.min.css b/dicoogle/src/main/resources/webapp/css/loaders.min.css
new file mode 100644
index 0000000..5ade517
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/loaders.min.css
@@ -0,0 +1 @@
+ at -webkit-keyframes scale{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}45%{-webkit-transform:scale(0.1);transform:scale(0.1);opacity:.7}80%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scale{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}45%{-webkit-transform:scale(0.1);transform:scale(0.1);opacity:.7}80%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.ball-pulse>div:nth-child(0){-webkit-animation:scale .75s 0s infinite cubic-bezi [...]
diff --git a/dicoogle/src/main/resources/webapp/css/react-bootstrap-table.min.css b/dicoogle/src/main/resources/webapp/css/react-bootstrap-table.min.css
new file mode 100644
index 0000000..510a4ce
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/react-bootstrap-table.min.css
@@ -0,0 +1 @@
+.react-bs-container .react-bs-table-container{border:1px solid #ddd}.react-bs-container .table-header{height:42px;border:hidden;overflow:hidden}.react-bs-container .table-header>table{border-top-style:hidden;border-right-style:hidden;border-left-style:hidden;width:100%}.react-bs-container .table-header>table>thead>tr{border-bottom-style:hidden}.react-bs-container .table-container>table>tbody>tr>td,.react-bs-container .table-container>table>thead>tr>th,.react-bs-container .table-header>ta [...]
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/css/simple-sidebar.css b/dicoogle/src/main/resources/webapp/css/simple-sidebar.css
new file mode 100644
index 0000000..ea0dc39
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/simple-sidebar.css
@@ -0,0 +1,125 @@
+/*!
+ * Start Bootstrap - Simple Sidebar HTML Template (http://startbootstrap.com)
+ * Code licensed under the Apache License v2.0.
+ * For details, see http://www.apache.org/licenses/LICENSE-2.0.
+ */
+
+/* Toggle Styles */
+
+#wrapper {
+    padding-left: 0;
+    -webkit-transition: all 0.5s ease;
+    -moz-transition: all 0.5s ease;
+    -o-transition: all 0.5s ease;
+    transition: all 0.5s ease;
+}
+
+#wrapper.toggled {
+    padding-left: 250px;
+}
+
+#sidebar-wrapper {
+    z-index: 1000;
+    position: fixed;
+    left: 250px;
+    width: 0;
+    height: 100%;
+    margin-left: -250px;
+    overflow-y: auto;
+    background: #000;
+    -webkit-transition: all 0.5s ease;
+    -moz-transition: all 0.5s ease;
+    -o-transition: all 0.5s ease;
+    transition: all 0.5s ease;
+}
+
+#wrapper.toggled #sidebar-wrapper {
+    width: 250px;
+}
+
+#page-content-wrapper {
+    width: 100%;
+    position: absolute;
+    padding: 15px;
+}
+
+#wrapper.toggled #page-content-wrapper {
+    position: absolute;
+    margin-right: -250px;
+}
+
+/* Sidebar Styles */
+
+.sidebar-nav {
+    position: relative;/* Estava absoluto e mudou  se para naop chatear*/
+    top: 0;
+    width: 250px;
+    margin: 0;
+    padding: 0;
+    list-style: none;
+}
+
+.sidebar-nav li {
+    text-indent: 20px;
+    line-height: 40px;
+}
+
+.sidebar-nav li a {
+    display: block;
+    text-decoration: none;
+    color: #999999;
+}
+
+.sidebar-nav li a:hover {
+    text-decoration: none;
+    color: #fff;
+    background: rgba(255,255,255,0.2);
+}
+
+.sidebar-nav li a:active,
+.sidebar-nav li a:focus {
+    text-decoration: none;
+}
+
+.sidebar-nav > .sidebar-brand {
+    height: 65px;
+    font-size: 18px;
+    line-height: 60px;
+}
+
+.sidebar-nav > .sidebar-brand a {
+    color: #999999;
+}
+
+.sidebar-nav > .sidebar-brand a:hover {
+    color: #fff;
+    background: none;
+}
+
+ at media(min-width:768px) {
+    #wrapper {
+        padding-left: 250px;
+    }
+
+    #wrapper.toggled {
+        padding-left: 0;
+    }
+
+    #sidebar-wrapper {
+        width: 250px;
+    }
+
+    #wrapper.toggled #sidebar-wrapper {
+        width: 0;
+    }
+
+    #page-content-wrapper {
+        padding: 20px;
+        position: relative;
+    }
+
+    #wrapper.toggled #page-content-wrapper {
+        position: relative;
+        margin-right: 0;
+    }
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/css/theme.css b/dicoogle/src/main/resources/webapp/css/theme.css
new file mode 100644
index 0000000..d94d423
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/css/theme.css
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 BMD Software, Lda.
+ * All Rights Reserved
+ *
+ * All information contained herein is, and remains the property of BMD Software, Lda. and its suppliers, if any.
+ * The intellectual and technical concepts contained herein are proprietary to BMD Software, Lda. and its suppliers,
+ * being protected by trade secret or copyright law. Dissemination of this information or reproduction of this
+ * material is strictly forbidden unless prior written permission is obtained from BMD Software, Lda.
+ */
+
+
+body {
+  padding-top: 150px;
+  padding-bottom: 30px;
+  padding-left: 80px;
+  
+  
+}
+
+#container
+{
+  margin-left: 150px;
+  margin-right: 150px;
+  
+}
+
+.about
+{
+  margin-left: 10%;
+  margin-right: 10%;
+
+}
+
+
+.config
+{
+  margin-left: 10%;
+  margin-right: 10%;
+
+}
+
+.devices
+{
+
+  margin-left: 250px;
+  margin-right: 250px;
+}
+
+.gridAbout{
+  margin-top:10px;
+  border: #cdcdcd medium solid;
+  border-radius: 10px;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+  
+}
+
+.theme-dropdown .dropdown-menu {
+  display: block;
+  position: static;
+  margin-bottom: 20px;
+}
+
+.theme-showcase > p > .btn {
+  margin: 5px 0;
+}
+
+
+.navbar-brand,
+.navbar-nav li a {
+  line-height: 100px;
+  height: 100px;
+  padding-top: 0;
+  font-size: 20px;
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/filetest.json b/dicoogle/src/main/resources/webapp/filetest.json
new file mode 100644
index 0000000..f5a4bdd
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/filetest.json
@@ -0,0 +1 @@
+[{"android":{"nRequests":18},"ios":{"nRequests":0},"other":{"nRequests":0},"date":"2015-03-23"},{"android":{"nRequests":1446},"ios":{"nRequests":31},"other":{"nRequests":1},"date":"2015-03-22"},{"android":{"nRequests":1296},"ios":{"nRequests":71},"other":{"nRequests":12},"date":"2015-03-21"},{"android":{"nRequests":1600},"ios":{"nRequests":5},"other":{"nRequests":0},"date":"2015-03-20"},{"android":{"nRequests":1406},"ios":{"nRequests":39},"other":{"nRequests":0},"date":"2015-03-19"},{"an [...]
diff --git a/dicoogle/src/main/resources/webapp/fonts/FontAwesome.otf b/dicoogle/src/main/resources/webapp/fonts/FontAwesome.otf
new file mode 100644
index 0000000..f7936cc
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/fonts/FontAwesome.otf differ
diff --git a/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.eot b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.eot
new file mode 100644
index 0000000..33b2bb8
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.eot differ
diff --git a/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.svg b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.svg
new file mode 100644
index 0000000..1ee89d4
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.svg
@@ -0,0 +1,565 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
+<metadata></metadata>
+<defs>
+<font id="fontawesomeregular" horiz-adv-x="1536" >
+<font-face units-per-em="1792" ascent="1536" descent="-256" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode=" "  horiz-adv-x="448" />
+<glyph unicode="&#x09;" horiz-adv-x="448" />
+<glyph unicode="&#xa0;" horiz-adv-x="448" />
+<glyph unicode="&#xa8;" horiz-adv-x="1792" />
+<glyph unicode="&#xa9;" horiz-adv-x="1792" />
+<glyph unicode="&#xae;" horiz-adv-x="1792" />
+<glyph unicode="&#xb4;" horiz-adv-x="1792" />
+<glyph unicode="&#xc6;" horiz-adv-x="1792" />
+<glyph unicode="&#xd8;" horiz-adv-x="1792" />
+<glyph unicode="&#x2000;" horiz-adv-x="768" />
+<glyph unicode="&#x2001;" horiz-adv-x="1537" />
+<glyph unicode="&#x2002;" horiz-adv-x="768" />
+<glyph unicode="&#x2003;" horiz-adv-x="1537" />
+<glyph unicode="&#x2004;" horiz-adv-x="512" />
+<glyph unicode="&#x2005;" horiz-adv-x="384" />
+<glyph unicode="&#x2006;" horiz-adv-x="256" />
+<glyph unicode="&#x2007;" horiz-adv-x="256" />
+<glyph unicode="&#x2008;" horiz-adv-x="192" />
+<glyph unicode="&#x2009;" horiz-adv-x="307" />
+<glyph unicode="&#x200a;" horiz-adv-x="85" />
+<glyph unicode="&#x202f;" horiz-adv-x="307" />
+<glyph unicode="&#x205f;" horiz-adv-x="384" />
+<glyph unicode="&#x2122;" horiz-adv-x="1792" />
+<glyph unicode="&#x221e;" horiz-adv-x="1792" />
+<glyph unicode="&#x2260;" horiz-adv-x="1792" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf000;" horiz-adv-x="1792" d="M1699 1350q0 -35 -43 -78l-632 -632v-768h320q26 0 45 -19t19 -45t-19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45t45 19h320v768l-632 632q-43 43 -43 78q0 23 18 36.5t38 17.5t43 4h1408q23 0 43 -4t38 -17.5t18 -36.5z" />
+<glyph unicode="&#xf001;" d="M1536 1312v-1120q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v537l-768 -237v-709q0 -50 -34 -89t-86 -60.5t-103.5 -32t-96.5 -10.5t-96.5 10.5t-103.5 32t-86 60.5t-34 89 t34 89t86 60.5t103.5 32t96.5 10.5q105 0 192 -39v967q0 31 19 56.5t49 35.5l832 256q12 4 28 4q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf002;" horiz-adv-x="1664" d="M1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -52 -38 -90t-90 -38q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5 t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5q0 -220 -124 -399l343 -343q37 -37 37 -90z" />
+<glyph unicode="&#xf003;" horiz-adv-x="1792" d="M1664 32v768q-32 -36 -69 -66q-268 -206 -426 -338q-51 -43 -83 -67t-86.5 -48.5t-102.5 -24.5h-1h-1q-48 0 -102.5 24.5t-86.5 48.5t-83 67q-158 132 -426 338q-37 30 -69 66v-768q0 -13 9.5 -22.5t22.5 -9.5h1472q13 0 22.5 9.5t9.5 22.5zM1664 1083v11v13.5t-0.5 13 t-3 12.5t-5.5 9t-9 7.5t-14 2.5h-1472q-13 0 -22.5 -9.5t-9.5 -22.5q0 -168 147 -284q193 -152 401 -317q6 -5 35 -29.5t46 -37.5t44.5 -31.5t50.5 -27.5t43 -9h1h1q20 0 43 9t50.5 27.5t44.5 31.5t46 37.5t35 [...]
+<glyph unicode="&#xf004;" horiz-adv-x="1792" d="M896 -128q-26 0 -44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t76 -68q36 36 76 68t95.5 68.5t120 58t126.5 21.5q224 0 351 -124t127 -344q0 -221 -229 -450l-623 -600 q-18 -18 -44 -18z" />
+<glyph unicode="&#xf005;" horiz-adv-x="1664" d="M1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -21 -10.5 -35.5t-30.5 -14.5q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455 l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf006;" horiz-adv-x="1664" d="M1137 532l306 297l-422 62l-189 382l-189 -382l-422 -62l306 -297l-73 -421l378 199l377 -199zM1664 889q0 -22 -26 -48l-363 -354l86 -500q1 -7 1 -20q0 -50 -41 -50q-19 0 -40 12l-449 236l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500 l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41t49 -41l225 -455l502 -73q56 -9 56 -46z" />
+<glyph unicode="&#xf007;" horiz-adv-x="1408" d="M1408 131q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5t43 97.5t62 81t85.5 53.5t111.5 20q9 0 42 -21.5t74.5 -48t108 -48t133.5 -21.5t133.5 21.5t108 48t74.5 48t42 21.5q61 0 111.5 -20t85.5 -53.5t62 -81 t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM1088 1024q0 -159 -112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf008;" horiz-adv-x="1920" d="M384 -64v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 320v128q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM384 704v128q0 26 -19 45t-45 19h-128 q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1408 -64v512q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-512q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM384 1088v128q0 26 -19 [...]
+<glyph unicode="&#xf009;" horiz-adv-x="1664" d="M768 512v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM768 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 512v-384q0 -52 -38 -90t-90 -38 h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90zM1664 1280v-384q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf00a;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 288v-192q0 -40 -28 -68t-68 -28h-320 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1152 800v-192q0 -40  [...]
+<glyph unicode="&#xf00b;" horiz-adv-x="1792" d="M512 288v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM512 800v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 288v-192q0 -40 -28 -68t-68 -28h-960 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h960q40 0 68 -28t28 -68zM512 1312v-192q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h320q40 0 68 -28t28 -68zM1792 800v-192q0 -40  [...]
+<glyph unicode="&#xf00c;" horiz-adv-x="1792" d="M1671 970q0 -40 -28 -68l-724 -724l-136 -136q-28 -28 -68 -28t-68 28l-136 136l-362 362q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -295l656 657q28 28 68 28t68 -28l136 -136q28 -28 28 -68z" />
+<glyph unicode="&#xf00d;" horiz-adv-x="1408" d="M1298 214q0 -40 -28 -68l-136 -136q-28 -28 -68 -28t-68 28l-294 294l-294 -294q-28 -28 -68 -28t-68 28l-136 136q-28 28 -28 68t28 68l294 294l-294 294q-28 28 -28 68t28 68l136 136q28 28 68 28t68 -28l294 -294l294 294q28 28 68 28t68 -28l136 -136q28 -28 28 -68 t-28 -68l-294 -294l294 -294q28 -28 28 -68z" />
+<glyph unicode="&#xf00e;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-224q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v224h-224q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h224v224q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5v-224h224 q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5zM1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343  [...]
+<glyph unicode="&#xf010;" horiz-adv-x="1664" d="M1024 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-576q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h576q13 0 22.5 -9.5t9.5 -22.5zM1152 704q0 185 -131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5z M1664 -128q0 -53 -37.5 -90.5t-90.5 -37.5q-54 0 -90 38l-343 342q-179 -124 -399 -124q-143 0 -273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150  [...]
+<glyph unicode="&#xf011;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61t-298 61t-245 164t-164 245t-61 298q0 182 80.5 343t226.5 270q43 32 95.5 25t83.5 -50q32 -42 24.5 -94.5t-49.5 -84.5q-98 -74 -151.5 -181t-53.5 -228q0 -104 40.5 -198.5t109.5 -163.5t163.5 -109.5 t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5q0 121 -53.5 228t-151.5 181q-42 32 -49.5 84.5t24.5 94.5q31 43 84 50t95 -25q146 -109 226.5 -270t80.5 -343zM896 1408v-640q0 -52 -38 -90t-90 -38t-90 38t-38 90v640q0  [...]
+<glyph unicode="&#xf012;" horiz-adv-x="1792" d="M256 96v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 224v-320q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1024 480v-576q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v576q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1408 864v-960q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM1792 1376v-1472q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t [...]
+<glyph unicode="&#xf013;" d="M1024 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1536 749v-222q0 -12 -8 -23t-20 -13l-185 -28q-19 -54 -39 -91q35 -50 107 -138q10 -12 10 -25t-9 -23q-27 -37 -99 -108t-94 -71q-12 0 -26 9l-138 108q-44 -23 -91 -38 q-16 -136 -29 -186q-7 -28 -36 -28h-222q-14 0 -24.5 8.5t-11.5 21.5l-28 184q-49 16 -90 37l-141 -107q-10 -9 -25 -9q-14 0 -25 11q-126 114 -165 168q-7 10 -7 23q0 12 8 23q15 21 51 66.5t54 70.5q-27 50 -41 99l-183 27q-13 2 -21 12.5 [...]
+<glyph unicode="&#xf014;" horiz-adv-x="1408" d="M512 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM768 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1024 800v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1152 76v948h-896v-948q0 -22 7 -40.5t14.5 -27t10.5 -8.5h832q3 0 10.5 8.5t14.5 27t7 40.5zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q [...]
+<glyph unicode="&#xf015;" horiz-adv-x="1664" d="M1408 544v-480q0 -26 -19 -45t-45 -19h-384v384h-256v-384h-384q-26 0 -45 19t-19 45v480q0 1 0.5 3t0.5 3l575 474l575 -474q1 -2 1 -6zM1631 613l-62 -74q-8 -9 -21 -11h-3q-13 0 -21 7l-692 577l-692 -577q-12 -8 -24 -7q-13 2 -21 11l-62 74q-8 10 -7 23.5t11 21.5 l719 599q32 26 76 26t76 -26l244 -204v195q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-408l219 -182q10 -8 11 -21.5t-7 -23.5z" />
+<glyph unicode="&#xf016;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z " />
+<glyph unicode="&#xf017;" d="M896 992v-448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf018;" horiz-adv-x="1920" d="M1111 540v4l-24 320q-1 13 -11 22.5t-23 9.5h-186q-13 0 -23 -9.5t-11 -22.5l-24 -320v-4q-1 -12 8 -20t21 -8h244q12 0 21 8t8 20zM1870 73q0 -73 -46 -73h-704q13 0 22 9.5t8 22.5l-20 256q-1 13 -11 22.5t-23 9.5h-272q-13 0 -23 -9.5t-11 -22.5l-20 -256 q-1 -13 8 -22.5t22 -9.5h-704q-46 0 -46 73q0 54 26 116l417 1044q8 19 26 33t38 14h339q-13 0 -23 -9.5t-11 -22.5l-15 -192q-1 -14 8 -23t22 -9h166q13 0 22 9t8 23l-15 192q-1 13 -11 22.5t-23 9.5h339q20 0 38 -14t2 [...]
+<glyph unicode="&#xf019;" horiz-adv-x="1664" d="M1280 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 416v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h465l135 -136 q58 -56 136 -56t136 56l136 136h464q40 0 68 -28t28 -68zM1339 985q17 -41 -14 -70l-448 -448q-18 -19 -45 -19t-45 19l-448 448q-31 29 -14 70q17 39 59 39h256v448q0 26 19 45t45 19h256q26 0 45 -19t19 -45v-448h256q4 [...]
+<glyph unicode="&#xf01a;" d="M1120 608q0 -12 -10 -24l-319 -319q-11 -9 -23 -9t-23 9l-320 320q-15 16 -7 35q8 20 30 20h192v352q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-352h192q14 0 23 -9t9 -23zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273 t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01b;" d="M1118 660q-8 -20 -30 -20h-192v-352q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v352h-192q-14 0 -23 9t-9 23q0 12 10 24l319 319q11 9 23 9t23 -9l320 -320q15 -16 7 -35zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198 t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01c;" d="M1023 576h316q-1 3 -2.5 8t-2.5 8l-212 496h-708l-212 -496q-1 -2 -2.5 -8t-2.5 -8h316l95 -192h320zM1536 546v-482q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v482q0 62 25 123l238 552q10 25 36.5 42t52.5 17h832q26 0 52.5 -17t36.5 -42l238 -552 q25 -61 25 -123z" />
+<glyph unicode="&#xf01d;" d="M1184 640q0 -37 -32 -55l-544 -320q-15 -9 -32 -9q-16 0 -32 8q-32 19 -32 56v640q0 37 32 56q33 18 64 -1l544 -320q32 -18 32 -55zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf01e;" d="M1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l138 138q-148 137 -349 137q-104 0 -198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5q119 0 225 52t179 147q7 10 23 12q14 0 25 -9 l137 -138q9 -8 9.5 -20.5t-7.5 -22.5q-109 -132 -264 -204.5t-327 -72.5q-156 0 -298 61t-245 164t-164 245t-61 298t61 298t164 245t245 164t298 61q147 0 284.5 -55.5t244.5 -156.5l130 129q29 31 70 14q39 -17 39 -59z" />
+<glyph unicode="&#xf021;" d="M1511 480q0 -5 -1 -7q-64 -268 -268 -434.5t-478 -166.5q-146 0 -282.5 55t-243.5 157l-129 -129q-19 -19 -45 -19t-45 19t-19 45v448q0 26 19 45t45 19h448q26 0 45 -19t19 -45t-19 -45l-137 -137q71 -66 161 -102t187 -36q134 0 250 65t186 179q11 17 53 117 q8 23 30 23h192q13 0 22.5 -9.5t9.5 -22.5zM1536 1280v-448q0 -26 -19 -45t-45 -19h-448q-26 0 -45 19t-19 45t19 45l138 138q-148 137 -349 137q-134 0 -250 -65t-186 -179q-11 -17 -53 -117q-8 -23 -30 -23h-199q-13 0 -22.5 9.5t-9.5 2 [...]
+<glyph unicode="&#xf022;" horiz-adv-x="1792" d="M384 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 608v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M384 864v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM1536 352v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-13 0 -22.5 9.5t-9.5  [...]
+<glyph unicode="&#xf023;" horiz-adv-x="1152" d="M320 768h512v192q0 106 -75 181t-181 75t-181 -75t-75 -181v-192zM1152 672v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v192q0 184 132 316t316 132t316 -132t132 -316v-192h32q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf024;" horiz-adv-x="1792" d="M320 1280q0 -72 -64 -110v-1266q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v1266q-64 38 -64 110q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -25 -12.5 -38.5t-39.5 -27.5q-215 -116 -369 -116q-61 0 -123.5 22t-108.5 48 t-115.5 48t-142.5 22q-192 0 -464 -146q-17 -9 -33 -9q-26 0 -45 19t-19 45v742q0 32 31 55q21 14 79 43q236 120 421 120q107 0 200 -29t219 -88q38 -19 88 -19q54 0 117.5 21t110 47t88 47t54.5 21q26 0 45 -1 [...]
+<glyph unicode="&#xf025;" horiz-adv-x="1664" d="M1664 650q0 -166 -60 -314l-20 -49l-185 -33q-22 -83 -90.5 -136.5t-156.5 -53.5v-32q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v576q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-32q71 0 130 -35.5t93 -95.5l68 12q29 95 29 193q0 148 -88 279t-236.5 209t-315.5 78 t-315.5 -78t-236.5 -209t-88 -279q0 -98 29 -193l68 -12q34 60 93 95.5t130 35.5v32q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-576q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v32q-88 0 -156.5 53.5t-90.5 136.5l-185  [...]
+<glyph unicode="&#xf026;" horiz-adv-x="768" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf027;" horiz-adv-x="1152" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142z" />
+<glyph unicode="&#xf028;" horiz-adv-x="1664" d="M768 1184v-1088q0 -26 -19 -45t-45 -19t-45 19l-333 333h-262q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h262l333 333q19 19 45 19t45 -19t19 -45zM1152 640q0 -76 -42.5 -141.5t-112.5 -93.5q-10 -5 -25 -5q-26 0 -45 18.5t-19 45.5q0 21 12 35.5t29 25t34 23t29 35.5 t12 57t-12 57t-29 35.5t-34 23t-29 25t-12 35.5q0 27 19 45.5t45 18.5q15 0 25 -5q70 -27 112.5 -93t42.5 -142zM1408 640q0 -153 -85 -282.5t-225 -188.5q-13 -5 -25 -5q-27 0 -46 19t-19 45q0 39 39 59q56  [...]
+<glyph unicode="&#xf029;" horiz-adv-x="1408" d="M384 384v-128h-128v128h128zM384 1152v-128h-128v128h128zM1152 1152v-128h-128v128h128zM128 129h384v383h-384v-383zM128 896h384v384h-384v-384zM896 896h384v384h-384v-384zM640 640v-640h-640v640h640zM1152 128v-128h-128v128h128zM1408 128v-128h-128v128h128z M1408 640v-384h-384v128h-128v-384h-128v640h384v-128h128v128h128zM640 1408v-640h-640v640h640zM1408 1408v-640h-640v640h640z" />
+<glyph unicode="&#xf02a;" horiz-adv-x="1792" d="M63 0h-63v1408h63v-1408zM126 1h-32v1407h32v-1407zM220 1h-31v1407h31v-1407zM377 1h-31v1407h31v-1407zM534 1h-62v1407h62v-1407zM660 1h-31v1407h31v-1407zM723 1h-31v1407h31v-1407zM786 1h-31v1407h31v-1407zM943 1h-63v1407h63v-1407zM1100 1h-63v1407h63v-1407z M1226 1h-63v1407h63v-1407zM1352 1h-63v1407h63v-1407zM1446 1h-63v1407h63v-1407zM1635 1h-94v1407h94v-1407zM1698 1h-32v1407h32v-1407zM1792 0h-63v1408h63v-1408z" />
+<glyph unicode="&#xf02b;" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91z" />
+<glyph unicode="&#xf02c;" horiz-adv-x="1920" d="M448 1088q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1515 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-53 0 -90 37l-715 716q-38 37 -64.5 101t-26.5 117v416q0 52 38 90t90 38h416q53 0 117 -26.5t102 -64.5 l715 -714q37 -39 37 -91zM1899 512q0 -53 -37 -90l-491 -492q-39 -37 -91 -37q-36 0 -59 14t-53 45l470 470q37 37 37 90q0 52 -37 91l-715 714q-38 38 -102 64.5t-117 26.5h224q53 0 117 -26.5t102 -64.5l7 [...]
+<glyph unicode="&#xf02d;" horiz-adv-x="1664" d="M1639 1058q40 -57 18 -129l-275 -906q-19 -64 -76.5 -107.5t-122.5 -43.5h-923q-77 0 -148.5 53.5t-99.5 131.5q-24 67 -2 127q0 4 3 27t4 37q1 8 -3 21.5t-3 19.5q2 11 8 21t16.5 23.5t16.5 23.5q23 38 45 91.5t30 91.5q3 10 0.5 30t-0.5 28q3 11 17 28t17 23 q21 36 42 92t25 90q1 9 -2.5 32t0.5 28q4 13 22 30.5t22 22.5q19 26 42.5 84.5t27.5 96.5q1 8 -3 25.5t-2 26.5q2 8 9 18t18 23t17 21q8 12 16.5 30.5t15 35t16 36t19.5 32t26.5 23.5t36 11.5t47.5 -5.5l-1 -3q38 9 51 [...]
+<glyph unicode="&#xf02e;" horiz-adv-x="1280" d="M1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf02f;" horiz-adv-x="1664" d="M384 0h896v256h-896v-256zM384 640h896v384h-160q-40 0 -68 28t-28 68v160h-640v-640zM1536 576q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 576v-416q0 -13 -9.5 -22.5t-22.5 -9.5h-224v-160q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68 v160h-224q-13 0 -22.5 9.5t-9.5 22.5v416q0 79 56.5 135.5t135.5 56.5h64v544q0 40 28 68t68 28h672q40 0 88 -20t76 -48l152 -152q28 -28 48 -76t20 -88v-256h64q79 0 135.5 -56.5t56.5 -135.5z" />
+<glyph unicode="&#xf030;" horiz-adv-x="1920" d="M960 864q119 0 203.5 -84.5t84.5 -203.5t-84.5 -203.5t-203.5 -84.5t-203.5 84.5t-84.5 203.5t84.5 203.5t203.5 84.5zM1664 1280q106 0 181 -75t75 -181v-896q0 -106 -75 -181t-181 -75h-1408q-106 0 -181 75t-75 181v896q0 106 75 181t181 75h224l51 136 q19 49 69.5 84.5t103.5 35.5h512q53 0 103.5 -35.5t69.5 -84.5l51 -136h224zM960 128q185 0 316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf031;" horiz-adv-x="1664" d="M725 977l-170 -450q33 0 136.5 -2t160.5 -2q19 0 57 2q-87 253 -184 452zM0 -128l2 79q23 7 56 12.5t57 10.5t49.5 14.5t44.5 29t31 50.5l237 616l280 724h75h53q8 -14 11 -21l205 -480q33 -78 106 -257.5t114 -274.5q15 -34 58 -144.5t72 -168.5q20 -45 35 -57 q19 -15 88 -29.5t84 -20.5q6 -38 6 -57q0 -4 -0.5 -13t-0.5 -13q-63 0 -190 8t-191 8q-76 0 -215 -7t-178 -8q0 43 4 78l131 28q1 0 12.5 2.5t15.5 3.5t14.5 4.5t15 6.5t11 8t9 11t2.5 14q0 16 -31 96.5t-72 177.5t-4 [...]
+<glyph unicode="&#xf032;" horiz-adv-x="1408" d="M555 15q74 -32 140 -32q376 0 376 335q0 114 -41 180q-27 44 -61.5 74t-67.5 46.5t-80.5 25t-84 10.5t-94.5 2q-73 0 -101 -10q0 -53 -0.5 -159t-0.5 -158q0 -8 -1 -67.5t-0.5 -96.5t4.5 -83.5t12 -66.5zM541 761q42 -7 109 -7q82 0 143 13t110 44.5t74.5 89.5t25.5 142 q0 70 -29 122.5t-79 82t-108 43.5t-124 14q-50 0 -130 -13q0 -50 4 -151t4 -152q0 -27 -0.5 -80t-0.5 -79q0 -46 1 -69zM0 -128l2 94q15 4 85 16t106 27q7 12 12.5 27t8.5 33.5t5.5 32.5t3 37.5t0.5 34v35.5v [...]
+<glyph unicode="&#xf033;" horiz-adv-x="1024" d="M0 -126l17 85q6 2 81.5 21.5t111.5 37.5q28 35 41 101q1 7 62 289t114 543.5t52 296.5v25q-24 13 -54.5 18.5t-69.5 8t-58 5.5l19 103q33 -2 120 -6.5t149.5 -7t120.5 -2.5q48 0 98.5 2.5t121 7t98.5 6.5q-5 -39 -19 -89q-30 -10 -101.5 -28.5t-108.5 -33.5 q-8 -19 -14 -42.5t-9 -40t-7.5 -45.5t-6.5 -42q-27 -148 -87.5 -419.5t-77.5 -355.5q-2 -9 -13 -58t-20 -90t-16 -83.5t-6 -57.5l1 -18q17 -4 185 -31q-3 -44 -16 -99q-11 0 -32.5 -1.5t-32.5 -1.5q-29 0 -87 10t-86 10q- [...]
+<glyph unicode="&#xf034;" horiz-adv-x="1792" d="M1744 128q33 0 42 -18.5t-11 -44.5l-126 -162q-20 -26 -49 -26t-49 26l-126 162q-20 26 -11 44.5t42 18.5h80v1024h-80q-33 0 -42 18.5t11 44.5l126 162q20 26 49 26t49 -26l126 -162q20 -26 11 -44.5t-42 -18.5h-80v-1024h80zM81 1407l54 -27q12 -5 211 -5q44 0 132 2 t132 2q36 0 107.5 -0.5t107.5 -0.5h293q6 0 21 -0.5t20.5 0t16 3t17.5 9t15 17.5l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 48t-14.5 73.5t-7.5 35.5q [...]
+<glyph unicode="&#xf035;" d="M81 1407l54 -27q12 -5 211 -5q44 0 132 2t132 2q70 0 246.5 1t304.5 0.5t247 -4.5q33 -1 56 31l42 1q4 0 14 -0.5t14 -0.5q2 -112 2 -336q0 -80 -5 -109q-39 -14 -68 -18q-25 44 -54 128q-3 9 -11 47.5t-15 73.5t-7 36q-10 13 -27 19q-5 2 -66 2q-30 0 -93 1t-103 1 t-94 -2t-96 -7q-9 -81 -8 -136l1 -152v52q0 -55 1 -154t1.5 -180t0.5 -153q0 -16 -2.5 -71.5t0 -91.5t12.5 -69q40 -21 124 -42.5t120 -37.5q5 -40 5 -50q0 -14 -3 -29l-34 -1q-76 -2 -218 8t-207 10q-50 0 -151 -9t-152 -9q-3 51 -3 [...]
+<glyph unicode="&#xf036;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf037;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1408 576v-128q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h896q26 0 45 -19t19 -45zM1664 960v-128q0 -26 -19 -45t-45 -19 h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1280 1344v-128q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h640q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf038;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1280q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1536q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1536q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1152q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf039;" horiz-adv-x="1792" d="M1792 192v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 576v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 960v-128q0 -26 -19 -45 t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-128q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf03a;" horiz-adv-x="1792" d="M256 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM256 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5 t9.5 -22.5zM256 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 - [...]
+<glyph unicode="&#xf03b;" horiz-adv-x="1792" d="M384 992v-576q0 -13 -9.5 -22.5t-22.5 -9.5q-14 0 -23 9l-288 288q-9 9 -9 23t9 23l288 288q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22 [...]
+<glyph unicode="&#xf03c;" horiz-adv-x="1792" d="M352 704q0 -14 -9 -23l-288 -288q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v576q0 13 9.5 22.5t22.5 9.5q14 0 23 -9l288 -288q9 -9 9 -23zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1728q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1728q13 0 22.5 -9.5 t9.5 -22.5zM1792 608v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1088q13 0 22.5 -9.5t9.5 -22.5zM1792 992v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1088q- [...]
+<glyph unicode="&#xf03d;" horiz-adv-x="1792" d="M1792 1184v-1088q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-403 403v-166q0 -119 -84.5 -203.5t-203.5 -84.5h-704q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h704q119 0 203.5 -84.5t84.5 -203.5v-165l403 402q18 19 45 19q12 0 25 -5 q39 -17 39 -59z" />
+<glyph unicode="&#xf03e;" horiz-adv-x="1920" d="M640 960q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1664 576v-448h-1408v192l320 320l160 -160l512 512zM1760 1280h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-1216q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5v1216 q0 13 -9.5 22.5t-22.5 9.5zM1920 1248v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf040;" d="M363 0l91 91l-235 235l-91 -91v-107h128v-128h107zM886 928q0 22 -22 22q-10 0 -17 -7l-542 -542q-7 -7 -7 -17q0 -22 22 -22q10 0 17 7l542 542q7 7 7 17zM832 1120l416 -416l-832 -832h-416v416zM1515 1024q0 -53 -37 -90l-166 -166l-416 416l166 165q36 38 90 38 q53 0 91 -38l235 -234q37 -39 37 -91z" />
+<glyph unicode="&#xf041;" horiz-adv-x="1024" d="M768 896q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1024 896q0 -109 -33 -179l-364 -774q-16 -33 -47.5 -52t-67.5 -19t-67.5 19t-46.5 52l-365 774q-33 70 -33 179q0 212 150 362t362 150t362 -150t150 -362z" />
+<glyph unicode="&#xf042;" d="M768 96v1088q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf043;" horiz-adv-x="1024" d="M512 384q0 36 -20 69q-1 1 -15.5 22.5t-25.5 38t-25 44t-21 50.5q-4 16 -21 16t-21 -16q-7 -23 -21 -50.5t-25 -44t-25.5 -38t-15.5 -22.5q-20 -33 -20 -69q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1024 512q0 -212 -150 -362t-362 -150t-362 150t-150 362 q0 145 81 275q6 9 62.5 90.5t101 151t99.5 178t83 201.5q9 30 34 47t51 17t51.5 -17t33.5 -47q28 -93 83 -201.5t99.5 -178t101 -151t62.5 -90.5q81 -127 81 -275z" />
+<glyph unicode="&#xf044;" horiz-adv-x="1792" d="M888 352l116 116l-152 152l-116 -116v-56h96v-96h56zM1328 1072q-16 16 -33 -1l-350 -350q-17 -17 -1 -33t33 1l350 350q17 17 1 33zM1408 478v-190q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-14 -14 -32 -8q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v126q0 13 9 22l64 64q15 15 35 7t20 -29zM1312 12 [...]
+<glyph unicode="&#xf045;" horiz-adv-x="1664" d="M1408 547v-259q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h255v0q13 0 22.5 -9.5t9.5 -22.5q0 -27 -26 -32q-77 -26 -133 -60q-10 -4 -16 -4h-112q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832 q66 0 113 47t47 113v214q0 19 18 29q28 13 54 37q16 16 35 8q21 -9 21 -29zM1645 1043l-384 -384q-18 -19 -45 -19q-12 0 -25 5q-39 17 -39 59v192h-160q-323 0 -438 -131q-119 -137 -74 -473q3 -23 -20 -34 [...]
+<glyph unicode="&#xf046;" horiz-adv-x="1664" d="M1408 606v-318q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q63 0 117 -25q15 -7 18 -23q3 -17 -9 -29l-49 -49q-10 -10 -23 -10q-3 0 -9 2q-23 6 -45 6h-832q-66 0 -113 -47t-47 -113v-832 q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v254q0 13 9 22l64 64q10 10 23 10q6 0 12 -3q20 -8 20 -29zM1639 1095l-814 -814q-24 -24 -57 -24t-57 24l-430 430q-24 24 -24 57t24 57l110 110q24 24 57 24t57 -24l263  [...]
+<glyph unicode="&#xf047;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-384v-384h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v384h-384v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45 t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h384v384h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45t-19 -45t-45 -19h-128v-384h384v128q0 26 19 45t45 19t45 -19l256  [...]
+<glyph unicode="&#xf048;" horiz-adv-x="1024" d="M979 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19z" />
+<glyph unicode="&#xf049;" horiz-adv-x="1792" d="M1747 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-9 9 -13 19v-678q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-678q4 11 13 19l710 710 q19 19 32 13t13 -32v-710q4 11 13 19z" />
+<glyph unicode="&#xf04a;" horiz-adv-x="1664" d="M1619 1395q19 19 32 13t13 -32v-1472q0 -26 -13 -32t-32 13l-710 710q-8 9 -13 19v-710q0 -26 -13 -32t-32 13l-710 710q-19 19 -19 45t19 45l710 710q19 19 32 13t13 -32v-710q5 11 13 19z" />
+<glyph unicode="&#xf04b;" horiz-adv-x="1408" d="M1384 609l-1328 -738q-23 -13 -39.5 -3t-16.5 36v1472q0 26 16.5 36t39.5 -3l1328 -738q23 -13 23 -31t-23 -31z" />
+<glyph unicode="&#xf04c;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45zM640 1344v-1408q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h512q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04d;" d="M1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf04e;" horiz-adv-x="1664" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q19 -19 19 -45t-19 -45l-710 -710q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf050;" horiz-adv-x="1792" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v710q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19l-710 -710 q-19 -19 -32 -13t-13 32v710q-5 -10 -13 -19z" />
+<glyph unicode="&#xf051;" horiz-adv-x="1024" d="M45 -115q-19 -19 -32 -13t-13 32v1472q0 26 13 32t32 -13l710 -710q8 -8 13 -19v678q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-1408q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v678q-5 -10 -13 -19z" />
+<glyph unicode="&#xf052;" horiz-adv-x="1538" d="M14 557l710 710q19 19 45 19t45 -19l710 -710q19 -19 13 -32t-32 -13h-1472q-26 0 -32 13t13 32zM1473 0h-1408q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1408q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19z" />
+<glyph unicode="&#xf053;" horiz-adv-x="1280" d="M1171 1235l-531 -531l531 -531q19 -19 19 -45t-19 -45l-166 -166q-19 -19 -45 -19t-45 19l-742 742q-19 19 -19 45t19 45l742 742q19 19 45 19t45 -19l166 -166q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf054;" horiz-adv-x="1280" d="M1107 659l-742 -742q-19 -19 -45 -19t-45 19l-166 166q-19 19 -19 45t19 45l531 531l-531 531q-19 19 -19 45t19 45l166 166q19 19 45 19t45 -19l742 -742q19 -19 19 -45t-19 -45z" />
+<glyph unicode="&#xf055;" d="M1216 576v128q0 26 -19 45t-45 19h-256v256q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-256h-256q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h256v-256q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v256h256q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5 t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf056;" d="M1216 576v128q0 26 -19 45t-45 19h-768q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h768q26 0 45 19t19 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5 t103 -385.5z" />
+<glyph unicode="&#xf057;" d="M1149 414q0 26 -19 45l-181 181l181 181q19 19 19 45q0 27 -19 46l-90 90q-19 19 -46 19q-26 0 -45 -19l-181 -181l-181 181q-19 19 -45 19q-27 0 -46 -19l-90 -90q-19 -19 -19 -46q0 -26 19 -45l181 -181l-181 -181q-19 -19 -19 -45q0 -27 19 -46l90 -90q19 -19 46 -19 q26 0 45 19l181 181l181 -181q19 -19 45 -19q27 0 46 19l90 90q19 19 19 46zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 - [...]
+<glyph unicode="&#xf058;" d="M1284 802q0 28 -18 46l-91 90q-19 19 -45 19t-45 -19l-408 -407l-226 226q-19 19 -45 19t-45 -19l-91 -90q-18 -18 -18 -46q0 -27 18 -45l362 -362q19 -19 45 -19q27 0 46 19l543 543q18 18 18 45zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf059;" d="M896 160v192q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h192q14 0 23 9t9 23zM1152 832q0 88 -55.5 163t-138.5 116t-170 41q-243 0 -371 -213q-15 -24 8 -42l132 -100q7 -6 19 -6q16 0 25 12q53 68 86 92q34 24 86 24q48 0 85.5 -26t37.5 -59 q0 -38 -20 -61t-68 -45q-63 -28 -115.5 -86.5t-52.5 -125.5v-36q0 -14 9 -23t23 -9h192q14 0 23 9t9 23q0 19 21.5 49.5t54.5 49.5q32 18 49 28.5t46 35t44.5 48t28 60.5t12.5 81zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-38 [...]
+<glyph unicode="&#xf05a;" d="M1024 160v160q0 14 -9 23t-23 9h-96v512q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h96v-320h-96q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23t23 -9h448q14 0 23 9t9 23zM896 1056v160q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-160q0 -14 9 -23 t23 -9h192q14 0 23 9t9 23zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05b;" d="M1197 512h-109q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h109q-32 108 -112.5 188.5t-188.5 112.5v-109q0 -26 -19 -45t-45 -19h-128q-26 0 -45 19t-19 45v109q-108 -32 -188.5 -112.5t-112.5 -188.5h109q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-109 q32 -108 112.5 -188.5t188.5 -112.5v109q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-109q108 32 188.5 112.5t112.5 188.5zM1536 704v-128q0 -26 -19 -45t-45 -19h-143q-37 -161 -154.5 -278.5t-278.5 -154.5v-143q0 -26 -19 -45t-45 -19h [...]
+<glyph unicode="&#xf05c;" d="M1097 457l-146 -146q-10 -10 -23 -10t-23 10l-137 137l-137 -137q-10 -10 -23 -10t-23 10l-146 146q-10 10 -10 23t10 23l137 137l-137 137q-10 10 -10 23t10 23l146 146q10 10 23 10t23 -10l137 -137l137 137q10 10 23 10t23 -10l146 -146q10 -10 10 -23t-10 -23 l-137 -137l137 -137q10 -10 10 -23t-10 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385. [...]
+<glyph unicode="&#xf05d;" d="M1171 723l-422 -422q-19 -19 -45 -19t-45 19l-294 294q-19 19 -19 45t19 45l102 102q19 19 45 19t45 -19l147 -147l275 275q19 19 45 19t45 -19l102 -102q19 -19 19 -45t-19 -45zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198 t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf05e;" d="M1312 643q0 161 -87 295l-754 -753q137 -89 297 -89q111 0 211.5 43.5t173.5 116.5t116 174.5t43 212.5zM313 344l755 754q-135 91 -300 91q-148 0 -273 -73t-198 -199t-73 -274q0 -162 89 -299zM1536 643q0 -157 -61 -300t-163.5 -246t-245 -164t-298.5 -61t-298.5 61 t-245 164t-163.5 246t-61 300t61 299.5t163.5 245.5t245 164t298.5 61t298.5 -61t245 -164t163.5 -245.5t61 -299.5z" />
+<glyph unicode="&#xf060;" d="M1536 640v-128q0 -53 -32.5 -90.5t-84.5 -37.5h-704l293 -294q38 -36 38 -90t-38 -90l-75 -76q-37 -37 -90 -37q-52 0 -91 37l-651 652q-37 37 -37 90q0 52 37 91l651 650q38 38 91 38q52 0 90 -38l75 -74q38 -38 38 -91t-38 -91l-293 -293h704q52 0 84.5 -37.5 t32.5 -90.5z" />
+<glyph unicode="&#xf061;" d="M1472 576q0 -54 -37 -91l-651 -651q-39 -37 -91 -37q-51 0 -90 37l-75 75q-38 38 -38 91t38 91l293 293h-704q-52 0 -84.5 37.5t-32.5 90.5v128q0 53 32.5 90.5t84.5 37.5h704l-293 294q-38 36 -38 90t38 90l75 75q38 38 90 38q53 0 91 -38l651 -651q37 -35 37 -90z" />
+<glyph unicode="&#xf062;" horiz-adv-x="1664" d="M1611 565q0 -51 -37 -90l-75 -75q-38 -38 -91 -38q-54 0 -90 38l-294 293v-704q0 -52 -37.5 -84.5t-90.5 -32.5h-128q-53 0 -90.5 32.5t-37.5 84.5v704l-294 -293q-36 -38 -90 -38t-90 38l-75 75q-38 38 -38 90q0 53 38 91l651 651q35 37 90 37q54 0 91 -37l651 -651 q37 -39 37 -91z" />
+<glyph unicode="&#xf063;" horiz-adv-x="1664" d="M1611 704q0 -53 -37 -90l-651 -652q-39 -37 -91 -37q-53 0 -90 37l-651 652q-38 36 -38 90q0 53 38 91l74 75q39 37 91 37q53 0 90 -37l294 -294v704q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-704l294 294q37 37 90 37q52 0 91 -37l75 -75q37 -39 37 -91z" />
+<glyph unicode="&#xf064;" horiz-adv-x="1792" d="M1792 896q0 -26 -19 -45l-512 -512q-19 -19 -45 -19t-45 19t-19 45v256h-224q-98 0 -175.5 -6t-154 -21.5t-133 -42.5t-105.5 -69.5t-80 -101t-48.5 -138.5t-17.5 -181q0 -55 5 -123q0 -6 2.5 -23.5t2.5 -26.5q0 -15 -8.5 -25t-23.5 -10q-16 0 -28 17q-7 9 -13 22 t-13.5 30t-10.5 24q-127 285 -127 451q0 199 53 333q162 403 875 403h224v256q0 26 19 45t45 19t45 -19l512 -512q19 -19 19 -45z" />
+<glyph unicode="&#xf065;" d="M755 480q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23zM1536 1344v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332 q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf066;" d="M768 576v-448q0 -26 -19 -45t-45 -19t-45 19l-144 144l-332 -332q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l332 332l-144 144q-19 19 -19 45t19 45t45 19h448q26 0 45 -19t19 -45zM1523 1248q0 -13 -10 -23l-332 -332l144 -144q19 -19 19 -45t-19 -45 t-45 -19h-448q-26 0 -45 19t-19 45v448q0 26 19 45t45 19t45 -19l144 -144l332 332q10 10 23 10t23 -10l114 -114q10 -10 10 -23z" />
+<glyph unicode="&#xf067;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-416v-416q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v416h-416q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h416v416q0 40 28 68t68 28h192q40 0 68 -28t28 -68v-416h416q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf068;" horiz-adv-x="1408" d="M1408 800v-192q0 -40 -28 -68t-68 -28h-1216q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h1216q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf069;" horiz-adv-x="1664" d="M1482 486q46 -26 59.5 -77.5t-12.5 -97.5l-64 -110q-26 -46 -77.5 -59.5t-97.5 12.5l-266 153v-307q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v307l-266 -153q-46 -26 -97.5 -12.5t-77.5 59.5l-64 110q-26 46 -12.5 97.5t59.5 77.5l266 154l-266 154 q-46 26 -59.5 77.5t12.5 97.5l64 110q26 46 77.5 59.5t97.5 -12.5l266 -153v307q0 52 38 90t90 38h128q52 0 90 -38t38 -90v-307l266 153q46 26 97.5 12.5t77.5 -59.5l64 -110q26 -46 12.5 -97.5t-59.5 -77.5l-266 -154z" />
+<glyph unicode="&#xf06a;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM896 161v190q0 14 -9 23.5t-22 9.5h-192q-13 0 -23 -10t-10 -23v-190q0 -13 10 -23t23 -10h192 q13 0 22 9.5t9 23.5zM894 505l18 621q0 12 -10 18q-10 8 -24 8h-220q-14 0 -24 -8q-10 -6 -10 -18l17 -621q0 -10 10 -17.5t24 -7.5h185q14 0 23.5 7.5t10.5 17.5z" />
+<glyph unicode="&#xf06b;" d="M928 180v56v468v192h-320v-192v-468v-56q0 -25 18 -38.5t46 -13.5h192q28 0 46 13.5t18 38.5zM472 1024h195l-126 161q-26 31 -69 31q-40 0 -68 -28t-28 -68t28 -68t68 -28zM1160 1120q0 40 -28 68t-68 28q-43 0 -69 -31l-125 -161h194q40 0 68 28t28 68zM1536 864v-320 q0 -14 -9 -23t-23 -9h-96v-416q0 -40 -28 -68t-68 -28h-1088q-40 0 -68 28t-28 68v416h-96q-14 0 -23 9t-9 23v320q0 14 9 23t23 9h440q-93 0 -158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5q107 0 168 -77l128 -165l128 165q61 [...]
+<glyph unicode="&#xf06c;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19q-172 0 -318 -49.5t-259.5 -134t-235.5 -219.5q-19 -21 -19 -45q0 -26 19 -45t45 -19q24 0 45 19q27 24 74 71t67 66q137 124 268.5 176t313.5 52q26 0 45 19t19 45zM1792 1030q0 -95 -20 -193q-46 -224 -184.5 -383t-357.5 -268 q-214 -108 -438 -108q-148 0 -286 47q-15 5 -88 42t-96 37q-16 0 -39.5 -32t-45 -70t-52.5 -70t-60 -32q-30 0 -51 11t-31 24t-27 42q-2 4 -6 11t-5.5 10t-3 9.5t-1.5 13.5q0 35 31 73.5t68 65.5t68 56t31 48q0 4 -14 3 [...]
+<glyph unicode="&#xf06d;" horiz-adv-x="1408" d="M1408 -160v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-1344q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h1344q13 0 22.5 -9.5t9.5 -22.5zM1152 896q0 -78 -24.5 -144t-64 -112.5t-87.5 -88t-96 -77.5t-87.5 -72t-64 -81.5t-24.5 -96.5q0 -96 67 -224l-4 1l1 -1 q-90 41 -160 83t-138.5 100t-113.5 122.5t-72.5 150.5t-27.5 184q0 78 24.5 144t64 112.5t87.5 88t96 77.5t87.5 72t64 81.5t24.5 96.5q0 94 -66 224l3 -1l-1 1q90 -41 160 -83t138.5 -100t113.5 -122.5t72.5 -150. [...]
+<glyph unicode="&#xf06e;" horiz-adv-x="1792" d="M1664 576q-152 236 -381 353q61 -104 61 -225q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5q0 121 61 225q-229 -117 -381 -353q133 -205 333.5 -326.5t434.5 -121.5t434.5 121.5t333.5 326.5zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5 t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1792 576q0 -34 -20 -69q-140 -230 -376.5 -368.5t-499.5 -138.5t-499.5 139t-376.5 368q-20 35 -20 69t20 69q140 229 376.5 [...]
+<glyph unicode="&#xf070;" horiz-adv-x="1792" d="M555 201l78 141q-87 63 -136 159t-49 203q0 121 61 225q-229 -117 -381 -353q167 -258 427 -375zM944 960q0 20 -14 34t-34 14q-125 0 -214.5 -89.5t-89.5 -214.5q0 -20 14 -34t34 -14t34 14t14 34q0 86 61 147t147 61q20 0 34 14t14 34zM1307 1151q0 -7 -1 -9 q-105 -188 -315 -566t-316 -567l-49 -89q-10 -16 -28 -16q-12 0 -134 70q-16 10 -16 28q0 12 44 87q-143 65 -263.5 173t-208.5 245q-20 31 -20 69t20 69q153 235 380 371t496 136q89 0 180 -17l54 97q10 16 28 16q5 0 [...]
+<glyph unicode="&#xf071;" horiz-adv-x="1792" d="M1024 161v190q0 14 -9.5 23.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -23.5v-190q0 -14 9.5 -23.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 23.5zM1022 535l18 459q0 12 -10 19q-13 11 -24 11h-220q-11 0 -24 -11q-10 -7 -10 -21l17 -457q0 -10 10 -16.5t24 -6.5h185 q14 0 23.5 6.5t10.5 16.5zM1008 1469l768 -1408q35 -63 -2 -126q-17 -29 -46.5 -46t-63.5 -17h-1536q-34 0 -63.5 17t-46.5 46q-37 63 -2 126l768 1408q17 31 47 49t65 18t65 -18t47 -49z" />
+<glyph unicode="&#xf072;" horiz-adv-x="1408" d="M1376 1376q44 -52 12 -148t-108 -172l-161 -161l160 -696q5 -19 -12 -33l-128 -96q-7 -6 -19 -6q-4 0 -7 1q-15 3 -21 16l-279 508l-259 -259l53 -194q5 -17 -8 -31l-96 -96q-9 -9 -23 -9h-2q-15 2 -24 13l-189 252l-252 189q-11 7 -13 23q-1 13 9 25l96 97q9 9 23 9 q6 0 8 -1l194 -53l259 259l-508 279q-14 8 -17 24q-2 16 9 27l128 128q14 13 30 8l665 -159l160 160q76 76 172 108t148 -12z" />
+<glyph unicode="&#xf073;" horiz-adv-x="1664" d="M128 -128h288v288h-288v-288zM480 -128h320v288h-320v-288zM128 224h288v320h-288v-320zM480 224h320v320h-320v-320zM128 608h288v288h-288v-288zM864 -128h320v288h-320v-288zM480 608h320v288h-320v-288zM1248 -128h288v288h-288v-288zM864 224h320v320h-320v-320z M512 1088v288q0 13 -9.5 22.5t-22.5 9.5h-64q-13 0 -22.5 -9.5t-9.5 -22.5v-288q0 -13 9.5 -22.5t22.5 -9.5h64q13 0 22.5 9.5t9.5 22.5zM1248 224h288v320h-288v-320zM864 608h320v288h-320v-288zM1248 608h28 [...]
+<glyph unicode="&#xf074;" horiz-adv-x="1792" d="M666 1055q-60 -92 -137 -273q-22 45 -37 72.5t-40.5 63.5t-51 56.5t-63 35t-81.5 14.5h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224q250 0 410 -225zM1792 256q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192q-32 0 -85 -0.5t-81 -1t-73 1 t-71 5t-64 10.5t-63 18.5t-58 28.5t-59 40t-55 53.5t-56 69.5q59 93 136 273q22 -45 37 -72.5t40.5 -63.5t51 -56.5t63 -35t81.5 -14.5h256v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1792 1152q0 -1 [...]
+<glyph unicode="&#xf075;" horiz-adv-x="1792" d="M1792 640q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22q-17 -2 -30.5 9t-17.5 29v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26 76q-157 89 -247.5 220t-90.5 281 q0 130 71 248.5t191 204.5t286 136.5t348 50.5q244 0 450 -85.5t326 -233t120 -321.5z" />
+<glyph unicode="&#xf076;" d="M1536 704v-128q0 -201 -98.5 -362t-274 -251.5t-395.5 -90.5t-395.5 90.5t-274 251.5t-98.5 362v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-128q0 -52 23.5 -90t53.5 -57t71 -30t64 -13t44 -2t44 2t64 13t71 30t53.5 57t23.5 90v128q0 26 19 45t45 19h384 q26 0 45 -19t19 -45zM512 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 -19t19 -45zM1536 1344v-384q0 -26 -19 -45t-45 -19h-384q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h384q26 0 45 [...]
+<glyph unicode="&#xf077;" horiz-adv-x="1792" d="M1683 205l-166 -165q-19 -19 -45 -19t-45 19l-531 531l-531 -531q-19 -19 -45 -19t-45 19l-166 165q-19 19 -19 45.5t19 45.5l742 741q19 19 45 19t45 -19l742 -741q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf078;" horiz-adv-x="1792" d="M1683 728l-742 -741q-19 -19 -45 -19t-45 19l-742 741q-19 19 -19 45.5t19 45.5l166 165q19 19 45 19t45 -19l531 -531l531 531q19 19 45 19t45 -19l166 -165q19 -19 19 -45.5t-19 -45.5z" />
+<glyph unicode="&#xf079;" horiz-adv-x="1920" d="M1280 32q0 -13 -9.5 -22.5t-22.5 -9.5h-960q-8 0 -13.5 2t-9 7t-5.5 8t-3 11.5t-1 11.5v13v11v160v416h-192q-26 0 -45 19t-19 45q0 24 15 41l320 384q19 22 49 22t49 -22l320 -384q15 -17 15 -41q0 -26 -19 -45t-45 -19h-192v-384h576q16 0 25 -11l160 -192q7 -11 7 -21 zM1920 448q0 -24 -15 -41l-320 -384q-20 -23 -49 -23t-49 23l-320 384q-15 17 -15 41q0 26 19 45t45 19h192v384h-576q-16 0 -25 12l-160 192q-7 9 -7 20q0 13 9.5 22.5t22.5 9.5h960q8 0 13.5 -2t9 -7t5.5  [...]
+<glyph unicode="&#xf07a;" horiz-adv-x="1664" d="M640 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1536 0q0 -52 -38 -90t-90 -38t-90 38t-38 90t38 90t90 38t90 -38t38 -90zM1664 1088v-512q0 -24 -16.5 -42.5t-40.5 -21.5l-1044 -122q13 -60 13 -70q0 -16 -24 -64h920q26 0 45 -19t19 -45 t-19 -45t-45 -19h-1024q-26 0 -45 19t-19 45q0 11 8 31.5t16 36t21.5 40t15.5 29.5l-177 823h-204q-26 0 -45 19t-19 45t19 45t45 19h256q16 0 28.5 -6.5t19.5 -15.5t13 -24.5t8 -26t5.5 -29.5t4.5 -26h1201q26 0 [...]
+<glyph unicode="&#xf07b;" horiz-adv-x="1664" d="M1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07c;" horiz-adv-x="1920" d="M1879 584q0 -31 -31 -66l-336 -396q-43 -51 -120.5 -86.5t-143.5 -35.5h-1088q-34 0 -60.5 13t-26.5 43q0 31 31 66l336 396q43 51 120.5 86.5t143.5 35.5h1088q34 0 60.5 -13t26.5 -43zM1536 928v-160h-832q-94 0 -197 -47.5t-164 -119.5l-337 -396l-5 -6q0 4 -0.5 12.5 t-0.5 12.5v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf07d;" horiz-adv-x="768" d="M704 1216q0 -26 -19 -45t-45 -19h-128v-1024h128q26 0 45 -19t19 -45t-19 -45l-256 -256q-19 -19 -45 -19t-45 19l-256 256q-19 19 -19 45t19 45t45 19h128v1024h-128q-26 0 -45 19t-19 45t19 45l256 256q19 19 45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf07e;" horiz-adv-x="1792" d="M1792 640q0 -26 -19 -45l-256 -256q-19 -19 -45 -19t-45 19t-19 45v128h-1024v-128q0 -26 -19 -45t-45 -19t-45 19l-256 256q-19 19 -19 45t19 45l256 256q19 19 45 19t45 -19t19 -45v-128h1024v128q0 26 19 45t45 19t45 -19l256 -256q19 -19 19 -45z" />
+<glyph unicode="&#xf080;" horiz-adv-x="2048" d="M640 640v-512h-256v512h256zM1024 1152v-1024h-256v1024h256zM2048 0v-128h-2048v1536h128v-1408h1920zM1408 896v-768h-256v768h256zM1792 1280v-1152h-256v1152h256z" />
+<glyph unicode="&#xf081;" d="M1280 926q-56 -25 -121 -34q68 40 93 117q-65 -38 -134 -51q-61 66 -153 66q-87 0 -148.5 -61.5t-61.5 -148.5q0 -29 5 -48q-129 7 -242 65t-192 155q-29 -50 -29 -106q0 -114 91 -175q-47 1 -100 26v-2q0 -75 50 -133.5t123 -72.5q-29 -8 -51 -8q-13 0 -39 4 q21 -63 74.5 -104t121.5 -42q-116 -90 -261 -90q-26 0 -50 3q148 -94 322 -94q112 0 210 35.5t168 95t120.5 137t75 162t24.5 168.5q0 18 -1 27q63 45 105 109zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t [...]
+<glyph unicode="&#xf082;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-188v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-532q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960z" />
+<glyph unicode="&#xf083;" horiz-adv-x="1792" d="M928 704q0 14 -9 23t-23 9q-66 0 -113 -47t-47 -113q0 -14 9 -23t23 -9t23 9t9 23q0 40 28 68t68 28q14 0 23 9t9 23zM1152 574q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM128 0h1536v128h-1536v-128zM1280 574q0 159 -112.5 271.5 t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM256 1216h384v128h-384v-128zM128 1024h1536v118v138h-828l-64 -128h-644v-128zM1792 1280v-1280q0 -53 -37.5 - [...]
+<glyph unicode="&#xf084;" horiz-adv-x="1792" d="M832 1024q0 80 -56 136t-136 56t-136 -56t-56 -136q0 -42 19 -83q-41 19 -83 19q-80 0 -136 -56t-56 -136t56 -136t136 -56t136 56t56 136q0 42 -19 83q41 -19 83 -19q80 0 136 56t56 136zM1683 320q0 -17 -49 -66t-66 -49q-9 0 -28.5 16t-36.5 33t-38.5 40t-24.5 26 l-96 -96l220 -220q28 -28 28 -68q0 -42 -39 -81t-81 -39q-40 0 -68 28l-671 671q-176 -131 -365 -131q-163 0 -265.5 102.5t-102.5 265.5q0 160 95 313t248 248t313 95q163 0 265.5 -102.5t102.5 -265.5q0 -189  [...]
+<glyph unicode="&#xf085;" horiz-adv-x="1920" d="M896 640q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM1664 128q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 1152q0 52 -38 90t-90 38t-90 -38t-38 -90q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1280 731v-185q0 -10 -7 -19.5t-16 -10.5l-155 -24q-11 -35 -32 -76q34 -48 90 -115q7 -10 7 -20q0 -12 -7 -19q-23 -30 -82.5 -89.5t-78.5 -59.5q-11 0 -21 7l-115 90q-37 -19 -77 -31q-11  [...]
+<glyph unicode="&#xf086;" horiz-adv-x="1792" d="M1408 768q0 -139 -94 -257t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q-124 72 -195 177t-71 224 q0 139 94 257t256.5 186.5t353.5 68.5t353.5 -68.5t256.5 -186.5t94 -257zM1792 512q0 -120 -71 -224.5t-195 -176.5q10 -24 20.5 -44t25 -38.5t22.5 -29t26 -29.5t23 -25q1 -1 4 -4.5t4.5 -5t4 -5t3.5 -5.5l2.5 [...]
+<glyph unicode="&#xf087;" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 768q0 51 -39 89.5t-89 38.5h-352q0 58 48 159.5t48 160.5q0 98 -32 145t-128 47q-26 -26 -38 -85t-30.5 -125.5t-59.5 -109.5q-22 -23 -77 -91q-4 -5 -23 -30t-31.5 -41t-34.5 -42.5 t-40 -44t-38.5 -35.5t-40 -27t-35.5 -9h-32v-640h32q13 0 31.5 -3t33 -6.5t38 -11t35 -11.5t35.5 -12.5t29 -10.5q211 -73 342 -73h121q192 0 192 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 4 [...]
+<glyph unicode="&#xf088;" d="M256 1088q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 512q0 35 -21.5 81t-53.5 47q15 17 25 47.5t10 55.5q0 69 -53 119q18 32 18 69t-17.5 73.5t-47.5 52.5q5 30 5 56q0 85 -49 126t-136 41h-128q-131 0 -342 -73q-5 -2 -29 -10.5 t-35.5 -12.5t-35 -11.5t-38 -11t-33 -6.5t-31.5 -3h-32v-640h32q16 0 35.5 -9t40 -27t38.5 -35.5t40 -44t34.5 -42.5t31.5 -41t23 -30q55 -68 77 -91q41 -43 59.5 -109.5t30.5 -125.5t38 -85q96 0 128 47t32 145q0 59 -48 160.5t-48 159.5h [...]
+<glyph unicode="&#xf089;" horiz-adv-x="896" d="M832 1504v-1339l-449 -236q-22 -12 -40 -12q-21 0 -31.5 14.5t-10.5 35.5q0 6 2 20l86 500l-364 354q-25 27 -25 48q0 37 56 46l502 73l225 455q19 41 49 41z" />
+<glyph unicode="&#xf08a;" horiz-adv-x="1792" d="M1664 940q0 81 -21.5 143t-55 98.5t-81.5 59.5t-94 31t-98 8t-112 -25.5t-110.5 -64t-86.5 -72t-60 -61.5q-18 -22 -49 -22t-49 22q-24 28 -60 61.5t-86.5 72t-110.5 64t-112 25.5t-98 -8t-94 -31t-81.5 -59.5t-55 -98.5t-21.5 -143q0 -168 187 -355l581 -560l580 559 q188 188 188 356zM1792 940q0 -221 -229 -450l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-10 8 -27.5 26t-55.5 65.5t-68 97.5t-53.5 121t-23.5 138q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -6 [...]
+<glyph unicode="&#xf08b;" horiz-adv-x="1664" d="M640 96q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-119 0 -203.5 84.5t-84.5 203.5v704q0 119 84.5 203.5t203.5 84.5h320q13 0 22.5 -9.5t9.5 -22.5q0 -4 1 -20t0.5 -26.5t-3 -23.5t-10 -19.5t-20.5 -6.5h-320q-66 0 -113 -47t-47 -113v-704 q0 -66 47 -113t113 -47h288h11h13t11.5 -1t11.5 -3t8 -5.5t7 -9t2 -13.5zM1568 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t4 [...]
+<glyph unicode="&#xf08c;" d="M237 122h231v694h-231v-694zM483 1030q-1 52 -36 86t-93 34t-94.5 -34t-36.5 -86q0 -51 35.5 -85.5t92.5 -34.5h1q59 0 95 34.5t36 85.5zM1068 122h231v398q0 154 -73 233t-193 79q-136 0 -209 -117h2v101h-231q3 -66 0 -694h231v388q0 38 7 56q15 35 45 59.5t74 24.5 q116 0 116 -157v-371zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf08d;" horiz-adv-x="1152" d="M480 672v448q0 14 -9 23t-23 9t-23 -9t-9 -23v-448q0 -14 9 -23t23 -9t23 9t9 23zM1152 320q0 -26 -19 -45t-45 -19h-429l-51 -483q-2 -12 -10.5 -20.5t-20.5 -8.5h-1q-27 0 -32 27l-76 485h-404q-26 0 -45 19t-19 45q0 123 78.5 221.5t177.5 98.5v512q-52 0 -90 38 t-38 90t38 90t90 38h640q52 0 90 -38t38 -90t-38 -90t-90 -38v-512q99 0 177.5 -98.5t78.5 -221.5z" />
+<glyph unicode="&#xf08e;" horiz-adv-x="1792" d="M1408 608v-320q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v320 q0 14 9 23t23 9h64q14 0 23 -9t9 -23zM1792 1472v-512q0 -26 -19 -45t-45 -19t-45 19l-176 176l-652 -652q-10 -10 -23 -10t-23 10l-114 114q-10 10 -10 23t10 23l652 652l-176 176q-19 19 -19 45t19 45t45 19h512q2 [...]
+<glyph unicode="&#xf090;" d="M1184 640q0 -26 -19 -45l-544 -544q-19 -19 -45 -19t-45 19t-19 45v288h-448q-26 0 -45 19t-19 45v384q0 26 19 45t45 19h448v288q0 26 19 45t45 19t45 -19l544 -544q19 -19 19 -45zM1536 992v-704q0 -119 -84.5 -203.5t-203.5 -84.5h-320q-13 0 -22.5 9.5t-9.5 22.5 q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q66 0 113 47t47 113v704q0 66 -47 113t-113 47h-288h-11h-13t-11.5 1t-11.5 3t-8 5.5t-7 9t-2 13.5q0 4 -1 20t-0.5 26.5t3 23.5t10 19.5t20.5 6.5h320q119 0 203.5 -84.5t84.5 -2 [...]
+<glyph unicode="&#xf091;" horiz-adv-x="1664" d="M458 653q-74 162 -74 371h-256v-96q0 -78 94.5 -162t235.5 -113zM1536 928v96h-256q0 -209 -74 -371q141 29 235.5 113t94.5 162zM1664 1056v-128q0 -71 -41.5 -143t-112 -130t-173 -97.5t-215.5 -44.5q-42 -54 -95 -95q-38 -34 -52.5 -72.5t-14.5 -89.5q0 -54 30.5 -91 t97.5 -37q75 0 133.5 -45.5t58.5 -114.5v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 69 58.5 114.5t133.5 45.5q67 0 97.5 37t30.5 91q0 51 -14.5 89.5t-52.5 72.5q-53 41 -95 95q-113 5 -215.5 4 [...]
+<glyph unicode="&#xf092;" d="M394 184q-8 -9 -20 3q-13 11 -4 19q8 9 20 -3q12 -11 4 -19zM352 245q9 -12 0 -19q-8 -6 -17 7t0 18q9 7 17 -6zM291 305q-5 -7 -13 -2q-10 5 -7 12q3 5 13 2q10 -5 7 -12zM322 271q-6 -7 -16 3q-9 11 -2 16q6 6 16 -3q9 -11 2 -16zM451 159q-4 -12 -19 -6q-17 4 -13 15 t19 7q16 -5 13 -16zM514 154q0 -11 -16 -11q-17 -2 -17 11q0 11 16 11q17 2 17 -11zM572 164q2 -10 -14 -14t-18 8t14 15q16 2 18 -9zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-224q-16 0 -24.5 1t-19.5 5t-16 14.5t-5 [...]
+<glyph unicode="&#xf093;" horiz-adv-x="1664" d="M1280 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1536 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 288v-320q0 -40 -28 -68t-68 -28h-1472q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h427q21 -56 70.5 -92 t110.5 -36h256q61 0 110.5 36t70.5 92h427q40 0 68 -28t28 -68zM1339 936q-17 -40 -59 -40h-256v-448q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v448h-256q-42 0 -59 40q-17 39 14 69l448 448q18 19 45 19t45 [...]
+<glyph unicode="&#xf094;" d="M1407 710q0 44 -7 113.5t-18 96.5q-12 30 -17 44t-9 36.5t-4 48.5q0 23 5 68.5t5 67.5q0 37 -10 55q-4 1 -13 1q-19 0 -58 -4.5t-59 -4.5q-60 0 -176 24t-175 24q-43 0 -94.5 -11.5t-85 -23.5t-89.5 -34q-137 -54 -202 -103q-96 -73 -159.5 -189.5t-88 -236t-24.5 -248.5 q0 -40 12.5 -120t12.5 -121q0 -23 -11 -66.5t-11 -65.5t12 -36.5t34 -14.5q24 0 72.5 11t73.5 11q57 0 169.5 -15.5t169.5 -15.5q181 0 284 36q129 45 235.5 152.5t166 245.5t59.5 275zM1535 712q0 -165 -70 -327.5t-196 -288t- [...]
+<glyph unicode="&#xf095;" horiz-adv-x="1408" d="M1408 296q0 -27 -10 -70.5t-21 -68.5q-21 -50 -122 -106q-94 -51 -186 -51q-27 0 -52.5 3.5t-57.5 12.5t-47.5 14.5t-55.5 20.5t-49 18q-98 35 -175 83q-128 79 -264.5 215.5t-215.5 264.5q-48 77 -83 175q-3 9 -18 49t-20.5 55.5t-14.5 47.5t-12.5 57.5t-3.5 52.5 q0 92 51 186q56 101 106 122q25 11 68.5 21t70.5 10q14 0 21 -3q18 -6 53 -76q11 -19 30 -54t35 -63.5t31 -53.5q3 -4 17.5 -25t21.5 -35.5t7 -28.5q0 -20 -28.5 -50t-62 -55t-62 -53t-28.5 -46q0 -9 5 -22.5t8.5  [...]
+<glyph unicode="&#xf096;" horiz-adv-x="1408" d="M1120 1280h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113v832q0 66 -47 113t-113 47zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832 q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf097;" horiz-adv-x="1280" d="M1152 1280h-1024v-1242l423 406l89 85l89 -85l423 -406v1242zM1164 1408q23 0 44 -9q33 -13 52.5 -41t19.5 -62v-1289q0 -34 -19.5 -62t-52.5 -41q-19 -8 -44 -8q-48 0 -83 32l-441 424l-441 -424q-36 -33 -83 -33q-23 0 -44 9q-33 13 -52.5 41t-19.5 62v1289 q0 34 19.5 62t52.5 41q21 9 44 9h1048z" />
+<glyph unicode="&#xf098;" d="M1280 343q0 11 -2 16q-3 8 -38.5 29.5t-88.5 49.5l-53 29q-5 3 -19 13t-25 15t-21 5q-18 0 -47 -32.5t-57 -65.5t-44 -33q-7 0 -16.5 3.5t-15.5 6.5t-17 9.5t-14 8.5q-99 55 -170.5 126.5t-126.5 170.5q-2 3 -8.5 14t-9.5 17t-6.5 15.5t-3.5 16.5q0 13 20.5 33.5t45 38.5 t45 39.5t20.5 36.5q0 10 -5 21t-15 25t-13 19q-3 6 -15 28.5t-25 45.5t-26.5 47.5t-25 40.5t-16.5 18t-16 2q-48 0 -101 -22q-46 -21 -80 -94.5t-34 -130.5q0 -16 2.5 -34t5 -30.5t9 -33t10 -29.5t12.5 -33t11 -30q60 -164 216. [...]
+<glyph unicode="&#xf099;" horiz-adv-x="1664" d="M1620 1128q-67 -98 -162 -167q1 -14 1 -42q0 -130 -38 -259.5t-115.5 -248.5t-184.5 -210.5t-258 -146t-323 -54.5q-271 0 -496 145q35 -4 78 -4q225 0 401 138q-105 2 -188 64.5t-114 159.5q33 -5 61 -5q43 0 85 11q-112 23 -185.5 111.5t-73.5 205.5v4q68 -38 146 -41 q-66 44 -105 115t-39 154q0 88 44 163q121 -149 294.5 -238.5t371.5 -99.5q-8 38 -8 74q0 134 94.5 228.5t228.5 94.5q140 0 236 -102q109 21 205 78q-37 -115 -142 -178q93 10 186 50z" />
+<glyph unicode="&#xf09a;" horiz-adv-x="1024" d="M959 1524v-264h-157q-86 0 -116 -36t-30 -108v-189h293l-39 -296h-254v-759h-306v759h-255v296h255v218q0 186 104 288.5t277 102.5q147 0 228 -12z" />
+<glyph unicode="&#xf09b;" d="M1536 640q0 -251 -146.5 -451.5t-378.5 -277.5q-27 -5 -39.5 7t-12.5 30v211q0 97 -52 142q57 6 102.5 18t94 39t81 66.5t53 105t20.5 150.5q0 121 -79 206q37 91 -8 204q-28 9 -81 -11t-92 -44l-38 -24q-93 26 -192 26t-192 -26q-16 11 -42.5 27t-83.5 38.5t-86 13.5 q-44 -113 -7 -204q-79 -85 -79 -206q0 -85 20.5 -150t52.5 -105t80.5 -67t94 -39t102.5 -18q-40 -36 -49 -103q-21 -10 -45 -15t-57 -5t-65.5 21.5t-55.5 62.5q-19 32 -48.5 52t-49.5 24l-20 3q-21 0 -29 -4.5t-5 -11.5t9 -14t13 - [...]
+<glyph unicode="&#xf09c;" horiz-adv-x="1664" d="M1664 960v-256q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45v256q0 106 -75 181t-181 75t-181 -75t-75 -181v-192h96q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h672v192q0 185 131.5 316.5t316.5 131.5 t316.5 -131.5t131.5 -316.5z" />
+<glyph unicode="&#xf09d;" horiz-adv-x="1920" d="M1760 1408q66 0 113 -47t47 -113v-1216q0 -66 -47 -113t-113 -47h-1600q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1600zM160 1280q-13 0 -22.5 -9.5t-9.5 -22.5v-224h1664v224q0 13 -9.5 22.5t-22.5 9.5h-1600zM1760 0q13 0 22.5 9.5t9.5 22.5v608h-1664v-608 q0 -13 9.5 -22.5t22.5 -9.5h1600zM256 128v128h256v-128h-256zM640 128v128h384v-128h-384z" />
+<glyph unicode="&#xf09e;" horiz-adv-x="1408" d="M384 192q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM896 69q2 -28 -17 -48q-18 -21 -47 -21h-135q-25 0 -43 16.5t-20 41.5q-22 229 -184.5 391.5t-391.5 184.5q-25 2 -41.5 20t-16.5 43v135q0 29 21 47q17 17 43 17h5q160 -13 306 -80.5 t259 -181.5q114 -113 181.5 -259t80.5 -306zM1408 67q2 -27 -18 -47q-18 -20 -46 -20h-143q-26 0 -44.5 17.5t-19.5 42.5q-12 215 -101 408.5t-231.5 336t-336 231.5t-408.5 102q-25 1 -42.5 19.5t-17.5 43.5 [...]
+<glyph unicode="&#xf0a0;" d="M1040 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1296 320q0 -33 -23.5 -56.5t-56.5 -23.5t-56.5 23.5t-23.5 56.5t23.5 56.5t56.5 23.5t56.5 -23.5t23.5 -56.5zM1408 160v320q0 13 -9.5 22.5t-22.5 9.5 h-1216q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h1216q13 0 22.5 9.5t9.5 22.5zM178 640h1180l-157 482q-4 13 -16 21.5t-26 8.5h-782q-14 0 -26 -8.5t-16 -21.5zM1536 480v-320q0 -66 -47 -113t-113 -47h-1216q- [...]
+<glyph unicode="&#xf0a1;" horiz-adv-x="1792" d="M1664 896q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5v-384q0 -52 -38 -90t-90 -38q-417 347 -812 380q-58 -19 -91 -66t-31 -100.5t40 -92.5q-20 -33 -23 -65.5t6 -58t33.5 -55t48 -50t61.5 -50.5q-29 -58 -111.5 -83t-168.5 -11.5t-132 55.5q-7 23 -29.5 87.5 t-32 94.5t-23 89t-15 101t3.5 98.5t22 110.5h-122q-66 0 -113 47t-47 113v192q0 66 47 113t113 47h480q435 0 896 384q52 0 90 -38t38 -90v-384zM1536 292v954q-394 -302 -768 -343v-270q377 -42 768 -341z" />
+<glyph unicode="&#xf0a2;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM246 128h1300q-266 300 -266 832q0 51 -24 105t-69 103t-121.5 80.5t-169.5 31.5t-169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -532 -266 -832z M1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 4 [...]
+<glyph unicode="&#xf0a3;" d="M1376 640l138 -135q30 -28 20 -70q-12 -41 -52 -51l-188 -48l53 -186q12 -41 -19 -70q-29 -31 -70 -19l-186 53l-48 -188q-10 -40 -51 -52q-12 -2 -19 -2q-31 0 -51 22l-135 138l-135 -138q-28 -30 -70 -20q-41 11 -51 52l-48 188l-186 -53q-41 -12 -70 19q-31 29 -19 70 l53 186l-188 48q-40 10 -52 51q-10 42 20 70l138 135l-138 135q-30 28 -20 70q12 41 52 51l188 48l-53 186q-12 41 19 70q29 31 70 19l186 -53l48 188q10 41 51 51q41 12 70 -19l135 -139l135 139q29 30 70 19q41 -10 51 -51l48 [...]
+<glyph unicode="&#xf0a4;" horiz-adv-x="1792" d="M256 192q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1664 768q0 51 -39 89.5t-89 38.5h-576q0 20 15 48.5t33 55t33 68t15 84.5q0 67 -44.5 97.5t-115.5 30.5q-24 0 -90 -139q-24 -44 -37 -65q-40 -64 -112 -145q-71 -81 -101 -106 q-69 -57 -140 -57h-32v-640h32q72 0 167 -32t193.5 -64t179.5 -32q189 0 189 167q0 26 -5 56q30 16 47.5 52.5t17.5 73.5t-18 69q53 50 53 119q0 25 -10 55.5t-25 47.5h331q52 0 90 38t38 90zM1792 769q0 -105 -75.5 -181t-1 [...]
+<glyph unicode="&#xf0a5;" horiz-adv-x="1792" d="M1376 128h32v640h-32q-35 0 -67.5 12t-62.5 37t-50 46t-49 54q-2 3 -3.5 4.5t-4 4.5t-4.5 5q-72 81 -112 145q-14 22 -38 68q-1 3 -10.5 22.5t-18.5 36t-20 35.5t-21.5 30.5t-18.5 11.5q-71 0 -115.5 -30.5t-44.5 -97.5q0 -43 15 -84.5t33 -68t33 -55t15 -48.5h-576 q-50 0 -89 -38.5t-39 -89.5q0 -52 38 -90t90 -38h331q-15 -17 -25 -47.5t-10 -55.5q0 -69 53 -119q-18 -32 -18 -69t17.5 -73.5t47.5 -52.5q-4 -24 -4 -56q0 -85 48.5 -126t135.5 -41q84 0 183 32t194 64t167 32z [...]
+<glyph unicode="&#xf0a6;" d="M1280 -64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 700q0 189 -167 189q-26 0 -56 -5q-16 30 -52.5 47.5t-73.5 17.5t-69 -18q-50 53 -119 53q-25 0 -55.5 -10t-47.5 -25v331q0 52 -38 90t-90 38q-51 0 -89.5 -39t-38.5 -89v-576 q-20 0 -48.5 15t-55 33t-68 33t-84.5 15q-67 0 -97.5 -44.5t-30.5 -115.5q0 -24 139 -90q44 -24 65 -37q64 -40 145 -112q81 -71 106 -101q57 -69 57 -140v-32h640v32q0 72 32 167t64 193.5t32 179.5zM1536 705q0 -133 -69 -322q-59 -164 - [...]
+<glyph unicode="&#xf0a7;" d="M1408 576q0 84 -32 183t-64 194t-32 167v32h-640v-32q0 -35 -12 -67.5t-37 -62.5t-46 -50t-54 -49q-9 -8 -14 -12q-81 -72 -145 -112q-22 -14 -68 -38q-3 -1 -22.5 -10.5t-36 -18.5t-35.5 -20t-30.5 -21.5t-11.5 -18.5q0 -71 30.5 -115.5t97.5 -44.5q43 0 84.5 15t68 33 t55 33t48.5 15v-576q0 -50 38.5 -89t89.5 -39q52 0 90 38t38 90v331q46 -35 103 -35q69 0 119 53q32 -18 69 -18t73.5 17.5t52.5 47.5q24 -4 56 -4q85 0 126 48.5t41 135.5zM1280 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -4 [...]
+<glyph unicode="&#xf0a8;" d="M1280 576v128q0 26 -19 45t-45 19h-502l189 189q19 19 19 45t-19 45l-91 91q-18 18 -45 18t-45 -18l-362 -362l-91 -91q-18 -18 -18 -45t18 -45l91 -91l362 -362q18 -18 45 -18t45 18l91 91q18 18 18 45t-18 45l-189 189h502q26 0 45 19t19 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0a9;" d="M1285 640q0 27 -18 45l-91 91l-362 362q-18 18 -45 18t-45 -18l-91 -91q-18 -18 -18 -45t18 -45l189 -189h-502q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h502l-189 -189q-19 -19 -19 -45t19 -45l91 -91q18 -18 45 -18t45 18l362 362l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0aa;" d="M1284 641q0 27 -18 45l-362 362l-91 91q-18 18 -45 18t-45 -18l-91 -91l-362 -362q-18 -18 -18 -45t18 -45l91 -91q18 -18 45 -18t45 18l189 189v-502q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v502l189 -189q19 -19 45 -19t45 19l91 91q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ab;" d="M1284 639q0 27 -18 45l-91 91q-18 18 -45 18t-45 -18l-189 -189v502q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-502l-189 189q-19 19 -45 19t-45 -19l-91 -91q-18 -18 -18 -45t18 -45l362 -362l91 -91q18 -18 45 -18t45 18l91 91l362 362q18 18 18 45zM1536 640 q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf0ac;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1042 887q-2 -1 -9.5 -9.5t-13.5 -9.5q2 0 4.5 5t5 11t3.5 7q6 7 22 15q14 6 52 12q34 8 51 -11 q-2 2 9.5 13t14.5 12q3 2 15 4.5t15 7.5l2 22q-12 -1 -17.5 7t-6.5 21q0 -2 -6 -8q0 7 -4.5 8t-11.5 -1t-9 -1q-10 3 -15 7.5t-8 16.5t-4 15q-2 5 -9.5 10.5t-9.5 10.5q-1 2 -2.5 5.5t-3 6.5t-4 5.5t-5.5 2.5t-7 -5t-7.5 -10t-4.5 -5 [...]
+<glyph unicode="&#xf0ad;" horiz-adv-x="1664" d="M384 64q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1028 484l-682 -682q-37 -37 -90 -37q-52 0 -91 37l-106 108q-38 36 -38 90q0 53 38 91l681 681q39 -98 114.5 -173.5t173.5 -114.5zM1662 919q0 -39 -23 -106q-47 -134 -164.5 -217.5 t-258.5 -83.5q-185 0 -316.5 131.5t-131.5 316.5t131.5 316.5t316.5 131.5q58 0 121.5 -16.5t107.5 -46.5q16 -11 16 -28t-16 -28l-293 -169v-224l193 -107q5 3 79 48.5t135.5 81t70.5 35.5q15 0 23.5 -10t8.5 -25z" />
+<glyph unicode="&#xf0ae;" horiz-adv-x="1792" d="M1024 128h640v128h-640v-128zM640 640h1024v128h-1024v-128zM1280 1152h384v128h-384v-128zM1792 320v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 832v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19 t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45zM1792 1344v-256q0 -26 -19 -45t-45 -19h-1664q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1664q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0b0;" horiz-adv-x="1408" d="M1403 1241q17 -41 -14 -70l-493 -493v-742q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-256 256q-19 19 -19 45v486l-493 493q-31 29 -14 70q17 39 59 39h1280q42 0 59 -39z" />
+<glyph unicode="&#xf0b1;" horiz-adv-x="1792" d="M640 1280h512v128h-512v-128zM1792 640v-480q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v480h672v-160q0 -26 19 -45t45 -19h320q26 0 45 19t19 45v160h672zM1024 640v-128h-256v128h256zM1792 1120v-384h-1792v384q0 66 47 113t113 47h352v160q0 40 28 68 t68 28h576q40 0 68 -28t28 -68v-160h352q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0b2;" d="M1283 995l-355 -355l355 -355l144 144q29 31 70 14q39 -17 39 -59v-448q0 -26 -19 -45t-45 -19h-448q-42 0 -59 40q-17 39 14 69l144 144l-355 355l-355 -355l144 -144q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l144 -144 l355 355l-355 355l-144 -144q-19 -19 -45 -19q-12 0 -24 5q-40 17 -40 59v448q0 26 19 45t45 19h448q42 0 59 -40q17 -39 -14 -69l-144 -144l355 -355l355 355l-144 144q-31 30 -14 69q17 40 59 40h448q26 0 45 -19t19 -45v-448q0  [...]
+<glyph unicode="&#xf0c0;" horiz-adv-x="1920" d="M593 640q-162 -5 -265 -128h-134q-82 0 -138 40.5t-56 118.5q0 353 124 353q6 0 43.5 -21t97.5 -42.5t119 -21.5q67 0 133 23q-5 -37 -5 -66q0 -139 81 -256zM1664 3q0 -120 -73 -189.5t-194 -69.5h-874q-121 0 -194 69.5t-73 189.5q0 53 3.5 103.5t14 109t26.5 108.5 t43 97.5t62 81t85.5 53.5t111.5 20q10 0 43 -21.5t73 -48t107 -48t135 -21.5t135 21.5t107 48t73 48t43 21.5q61 0 111.5 -20t85.5 -53.5t62 -81t43 -97.5t26.5 -108.5t14 -109t3.5 -103.5zM640 1280q0 -106 -7 [...]
+<glyph unicode="&#xf0c1;" horiz-adv-x="1664" d="M1456 320q0 40 -28 68l-208 208q-28 28 -68 28q-42 0 -72 -32q3 -3 19 -18.5t21.5 -21.5t15 -19t13 -25.5t3.5 -27.5q0 -40 -28 -68t-68 -28q-15 0 -27.5 3.5t-25.5 13t-19 15t-21.5 21.5t-18.5 19q-33 -31 -33 -73q0 -40 28 -68l206 -207q27 -27 68 -27q40 0 68 26 l147 146q28 28 28 67zM753 1025q0 40 -28 68l-206 207q-28 28 -68 28q-39 0 -68 -27l-147 -146q-28 -28 -28 -67q0 -40 28 -68l208 -208q27 -27 68 -27q42 0 72 31q-3 3 -19 18.5t-21.5 21.5t-15 19t-13 25.5t-3. [...]
+<glyph unicode="&#xf0c2;" horiz-adv-x="1920" d="M1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088q-185 0 -316.5 131.5t-131.5 316.5q0 132 71 241.5t187 163.5q-2 28 -2 43q0 212 150 362t362 150q158 0 286.5 -88t187.5 -230q70 62 166 62q106 0 181 -75t75 -181q0 -75 -41 -138q129 -30 213 -134.5t84 -239.5z " />
+<glyph unicode="&#xf0c3;" horiz-adv-x="1664" d="M1527 88q56 -89 21.5 -152.5t-140.5 -63.5h-1152q-106 0 -140.5 63.5t21.5 152.5l503 793v399h-64q-26 0 -45 19t-19 45t19 45t45 19h512q26 0 45 -19t19 -45t-19 -45t-45 -19h-64v-399zM748 813l-272 -429h712l-272 429l-20 31v37v399h-128v-399v-37z" />
+<glyph unicode="&#xf0c4;" horiz-adv-x="1792" d="M960 640q26 0 45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45t19 45t45 19zM1260 576l507 -398q28 -20 25 -56q-5 -35 -35 -51l-128 -64q-13 -7 -29 -7q-17 0 -31 8l-690 387l-110 -66q-8 -4 -12 -5q14 -49 10 -97q-7 -77 -56 -147.5t-132 -123.5q-132 -84 -277 -84 q-136 0 -222 78q-90 84 -79 207q7 76 56 147t131 124q132 84 278 84q83 0 151 -31q9 13 22 22l122 73l-122 73q-13 9 -22 22q-68 -31 -151 -31q-146 0 -278 84q-82 53 -131 124t-56 147q-5 59 15.5 113t63.5 93q85 [...]
+<glyph unicode="&#xf0c5;" horiz-adv-x="1792" d="M1696 1152q40 0 68 -28t28 -68v-1216q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v288h-544q-40 0 -68 28t-28 68v672q0 40 20 88t48 76l408 408q28 28 76 48t88 20h416q40 0 68 -28t28 -68v-328q68 40 128 40h416zM1152 939l-299 -299h299v299zM512 1323l-299 -299 h299v299zM708 676l316 316v416h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h512v256q0 40 20 88t48 76zM1664 -128v1152h-384v-416q0 -40 -28 -68t-68 -28h-416v-640h896z" />
+<glyph unicode="&#xf0c6;" horiz-adv-x="1408" d="M1404 151q0 -117 -79 -196t-196 -79q-135 0 -235 100l-777 776q-113 115 -113 271q0 159 110 270t269 111q158 0 273 -113l605 -606q10 -10 10 -22q0 -16 -30.5 -46.5t-46.5 -30.5q-13 0 -23 10l-606 607q-79 77 -181 77q-106 0 -179 -75t-73 -181q0 -105 76 -181 l776 -777q63 -63 145 -63q64 0 106 42t42 106q0 82 -63 145l-581 581q-26 24 -60 24q-29 0 -48 -19t-19 -48q0 -32 25 -59l410 -410q10 -10 10 -22q0 -16 -31 -47t-47 -31q-12 0 -22 10l-410 410q-63 61 -63 149q0  [...]
+<glyph unicode="&#xf0c7;" d="M384 0h768v384h-768v-384zM1280 0h128v896q0 14 -10 38.5t-20 34.5l-281 281q-10 10 -34 20t-39 10v-416q0 -40 -28 -68t-68 -28h-576q-40 0 -68 28t-28 68v416h-128v-1280h128v416q0 40 28 68t68 28h832q40 0 68 -28t28 -68v-416zM896 928v320q0 13 -9.5 22.5t-22.5 9.5 h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-320q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5zM1536 896v-928q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h928q40 0 88 -20t76 -48l280 -280q28 [...]
+<glyph unicode="&#xf0c8;" d="M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0c9;" d="M1536 192v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 704v-128q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1536 1216v-128q0 -26 -19 -45 t-45 -19h-1408q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0ca;" horiz-adv-x="1792" d="M384 128q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM384 640q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 224v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5 t22.5 9.5h1216q13 0 22.5 -9.5t9.5 -22.5zM384 1152q0 -80 -56 -136t-136 -56t-136 56t-56 136t56 136t136 56t136 -56t56 -136zM1792 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1216q-13 0 -22.5 9.5t-9.5 22. [...]
+<glyph unicode="&#xf0cb;" horiz-adv-x="1792" d="M381 -84q0 -80 -54.5 -126t-135.5 -46q-106 0 -172 66l57 88q49 -45 106 -45q29 0 50.5 14.5t21.5 42.5q0 64 -105 56l-26 56q8 10 32.5 43.5t42.5 54t37 38.5v1q-16 0 -48.5 -1t-48.5 -1v-53h-106v152h333v-88l-95 -115q51 -12 81 -49t30 -88zM383 543v-159h-362 q-6 36 -6 54q0 51 23.5 93t56.5 68t66 47.5t56.5 43.5t23.5 45q0 25 -14.5 38.5t-39.5 13.5q-46 0 -81 -58l-85 59q24 51 71.5 79.5t105.5 28.5q73 0 123 -41.5t50 -112.5q0 -50 -34 -91.5t-75 -64.5t-75.5 -50.5t- [...]
+<glyph unicode="&#xf0cc;" horiz-adv-x="1792" d="M1760 640q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-1728q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h1728zM483 704q-28 35 -51 80q-48 97 -48 188q0 181 134 309q133 127 393 127q50 0 167 -19q66 -12 177 -48q10 -38 21 -118q14 -123 14 -183q0 -18 -5 -45l-12 -3l-84 6 l-14 2q-50 149 -103 205q-88 91 -210 91q-114 0 -182 -59q-67 -58 -67 -146q0 -73 66 -140t279 -129q69 -20 173 -66q58 -28 95 -52h-743zM990 448h411q7 -39 7 -92q0 -111 -41 -212q-23 -55 -71 -104q-37 -3 [...]
+<glyph unicode="&#xf0cd;" d="M48 1313q-37 2 -45 4l-3 88q13 1 40 1q60 0 112 -4q132 -7 166 -7q86 0 168 3q116 4 146 5q56 0 86 2l-1 -14l2 -64v-9q-60 -9 -124 -9q-60 0 -79 -25q-13 -14 -13 -132q0 -13 0.5 -32.5t0.5 -25.5l1 -229l14 -280q6 -124 51 -202q35 -59 96 -92q88 -47 177 -47 q104 0 191 28q56 18 99 51q48 36 65 64q36 56 53 114q21 73 21 229q0 79 -3.5 128t-11 122.5t-13.5 159.5l-4 59q-5 67 -24 88q-34 35 -77 34l-100 -2l-14 3l2 86h84l205 -10q76 -3 196 10l18 -2q6 -38 6 -51q0 -7 -4 -31q-45 -12 -84 -1 [...]
+<glyph unicode="&#xf0ce;" horiz-adv-x="1664" d="M512 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 160v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23 v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM512 928v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h320q14 0 23 9t9 23zM1024 544v192q0 14 -9 23t-23 9h-320q-14 0 -23 -9t-9 -2 [...]
+<glyph unicode="&#xf0d0;" horiz-adv-x="1664" d="M1190 955l293 293l-107 107l-293 -293zM1637 1248q0 -27 -18 -45l-1286 -1286q-18 -18 -45 -18t-45 18l-198 198q-18 18 -18 45t18 45l1286 1286q18 18 45 18t45 -18l198 -198q18 -18 18 -45zM286 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM636 1276 l196 -60l-196 -60l-60 -196l-60 196l-196 60l196 60l60 196zM1566 798l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98zM926 1438l98 -30l-98 -30l-30 -98l-30 98l-98 30l98 30l30 98z" />
+<glyph unicode="&#xf0d1;" horiz-adv-x="1792" d="M640 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM256 640h384v256h-158q-13 0 -22 -9l-195 -195q-9 -9 -9 -22v-30zM1536 128q0 52 -38 90t-90 38t-90 -38t-38 -90t38 -90t90 -38t90 38t38 90zM1792 1216v-1024q0 -15 -4 -26.5t-13.5 -18.5 t-16.5 -11.5t-23.5 -6t-22.5 -2t-25.5 0t-22.5 0.5q0 -106 -75 -181t-181 -75t-181 75t-75 181h-384q0 -106 -75 -181t-181 -75t-181 75t-75 181h-64q-3 0 -22.5 -0.5t-25.5 0t-22.5 2t-23.5 6t-16.5 11.5t-13.5  [...]
+<glyph unicode="&#xf0d2;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103q-111 0 -218 32q59 93 78 164q9 34 54 211q20 -39 73 -67.5t114 -28.5q121 0 216 68.5t147 188.5t52 270q0 114 -59.5 214t-172.5 163t-255 63q-105 0 -196 -29t-154.5 -77t-109 -110.5t-67 -129.5t-21.5 -134 q0 -104 40 -183t117 -111q30 -12 38 20q2 7 8 31t8 30q6 23 -11 43q-51 61 -51 151q0 151 104.5 259.5t273.5 108.5q151 0 235.5 -82t84.5 -213q0 -170 -68.5 -289t-175.5 -119q-61 0 -98 43.5t-23 104.5q8 35 26.5 93.5t30 103t11 [...]
+<glyph unicode="&#xf0d3;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-725q85 122 108 210q9 34 53 209q21 -39 73.5 -67t112.5 -28q181 0 295.5 147.5t114.5 373.5q0 84 -35 162.5t-96.5 139t-152.5 97t-197 36.5q-104 0 -194.5 -28.5t-153 -76.5 t-107.5 -109.5t-66.5 -128t-21.5 -132.5q0 -102 39.5 -180t116.5 -110q13 -5 23.5 0t14.5 19q10 44 15 61q6 23 -11 42q-50 62 -50 150q0 150 103.5 256.5t270.5 106.5q149 0 232.5 -81t83.5 -210q0 -168 -67.5 -286t-173.5 -118q-60 0 - [...]
+<glyph unicode="&#xf0d4;" d="M829 318q0 -76 -58.5 -112.5t-139.5 -36.5q-41 0 -80.5 9.5t-75.5 28.5t-58 53t-22 78q0 46 25 80t65.5 51.5t82 25t84.5 7.5q20 0 31 -2q2 -1 23 -16.5t26 -19t23 -18t24.5 -22t19 -22.5t17 -26t9 -26.5t4.5 -31.5zM755 863q0 -60 -33 -99.5t-92 -39.5q-53 0 -93 42.5 t-57.5 96.5t-17.5 106q0 61 32 104t92 43q53 0 93.5 -45t58 -101t17.5 -107zM861 1120l88 64h-265q-85 0 -161 -32t-127.5 -98t-51.5 -153q0 -93 64.5 -154.5t158.5 -61.5q22 0 43 3q-13 -29 -13 -54q0 -44 40 -94q-175 -12 -257  [...]
+<glyph unicode="&#xf0d5;" horiz-adv-x="1664" d="M735 740q0 -36 32 -70.5t77.5 -68t90.5 -73.5t77 -104t32 -142q0 -90 -48 -173q-72 -122 -211 -179.5t-298 -57.5q-132 0 -246.5 41.5t-171.5 137.5q-37 60 -37 131q0 81 44.5 150t118.5 115q131 82 404 100q-32 42 -47.5 74t-15.5 73q0 36 21 85q-46 -4 -68 -4 q-148 0 -249.5 96.5t-101.5 244.5q0 82 36 159t99 131q77 66 182.5 98t217.5 32h418l-138 -88h-131q74 -63 112 -133t38 -160q0 -72 -24.5 -129.5t-59 -93t-69.5 -65t-59.5 -61.5t-24.5 -66zM589 836q38 0 78 16.5t66 [...]
+<glyph unicode="&#xf0d6;" horiz-adv-x="1920" d="M768 384h384v96h-128v448h-114l-148 -137l77 -80q42 37 55 57h2v-288h-128v-96zM1280 640q0 -70 -21 -142t-59.5 -134t-101.5 -101t-138 -39t-138 39t-101.5 101t-59.5 134t-21 142t21 142t59.5 134t101.5 101t138 39t138 -39t101.5 -101t59.5 -134t21 -142zM1792 384 v512q-106 0 -181 75t-75 181h-1152q0 -106 -75 -181t-181 -75v-512q106 0 181 -75t75 -181h1152q0 106 75 181t181 75zM1920 1216v-1152q0 -26 -19 -45t-45 -19h-1792q-26 0 -45 19t-19 45v1152q0 26 19 45t45  [...]
+<glyph unicode="&#xf0d7;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0d8;" horiz-adv-x="1024" d="M1024 320q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0d9;" horiz-adv-x="640" d="M640 1088v-896q0 -26 -19 -45t-45 -19t-45 19l-448 448q-19 19 -19 45t19 45l448 448q19 19 45 19t45 -19t19 -45z" />
+<glyph unicode="&#xf0da;" horiz-adv-x="640" d="M576 640q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19t-19 45v896q0 26 19 45t45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0db;" horiz-adv-x="1664" d="M160 0h608v1152h-640v-1120q0 -13 9.5 -22.5t22.5 -9.5zM1536 32v1120h-640v-1152h608q13 0 22.5 9.5t9.5 22.5zM1664 1248v-1216q0 -66 -47 -113t-113 -47h-1344q-66 0 -113 47t-47 113v1216q0 66 47 113t113 47h1344q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf0dc;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45zM1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0dd;" horiz-adv-x="1024" d="M1024 448q0 -26 -19 -45l-448 -448q-19 -19 -45 -19t-45 19l-448 448q-19 19 -19 45t19 45t45 19h896q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf0de;" horiz-adv-x="1024" d="M1024 832q0 -26 -19 -45t-45 -19h-896q-26 0 -45 19t-19 45t19 45l448 448q19 19 45 19t45 -19l448 -448q19 -19 19 -45z" />
+<glyph unicode="&#xf0e0;" horiz-adv-x="1792" d="M1792 826v-794q0 -66 -47 -113t-113 -47h-1472q-66 0 -113 47t-47 113v794q44 -49 101 -87q362 -246 497 -345q57 -42 92.5 -65.5t94.5 -48t110 -24.5h1h1q51 0 110 24.5t94.5 48t92.5 65.5q170 123 498 345q57 39 100 87zM1792 1120q0 -79 -49 -151t-122 -123 q-376 -261 -468 -325q-10 -7 -42.5 -30.5t-54 -38t-52 -32.5t-57.5 -27t-50 -9h-1h-1q-23 0 -50 9t-57.5 27t-52 32.5t-54 38t-42.5 30.5q-91 64 -262 182.5t-205 142.5q-62 42 -117 115.5t-55 136.5q0 78 41.5 130t11 [...]
+<glyph unicode="&#xf0e1;" d="M349 911v-991h-330v991h330zM370 1217q1 -73 -50.5 -122t-135.5 -49h-2q-82 0 -132 49t-50 122q0 74 51.5 122.5t134.5 48.5t133 -48.5t51 -122.5zM1536 488v-568h-329v530q0 105 -40.5 164.5t-126.5 59.5q-63 0 -105.5 -34.5t-63.5 -85.5q-11 -30 -11 -81v-553h-329 q2 399 2 647t-1 296l-1 48h329v-144h-2q20 32 41 56t56.5 52t87 43.5t114.5 15.5q171 0 275 -113.5t104 -332.5z" />
+<glyph unicode="&#xf0e2;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 - [...]
+<glyph unicode="&#xf0e3;" horiz-adv-x="1792" d="M1771 0q0 -53 -37 -90l-107 -108q-39 -37 -91 -37q-53 0 -90 37l-363 364q-38 36 -38 90q0 53 43 96l-256 256l-126 -126q-14 -14 -34 -14t-34 14q2 -2 12.5 -12t12.5 -13t10 -11.5t10 -13.5t6 -13.5t5.5 -16.5t1.5 -18q0 -38 -28 -68q-3 -3 -16.5 -18t-19 -20.5 t-18.5 -16.5t-22 -15.5t-22 -9t-26 -4.5q-40 0 -68 28l-408 408q-28 28 -28 68q0 13 4.5 26t9 22t15.5 22t16.5 18.5t20.5 19t18 16.5q30 28 68 28q10 0 18 -1.5t16.5 -5.5t13.5 -6t13.5 -10t11.5 -10t13 -12.5t12 - [...]
+<glyph unicode="&#xf0e4;" horiz-adv-x="1792" d="M384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM576 832q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1004 351l101 382q6 26 -7.5 48.5t-38.5 29.5 t-48 -6.5t-30 -39.5l-101 -382q-60 -5 -107 -43.5t-63 -98.5q-20 -77 20 -146t117 -89t146 20t89 117q16 60 -6 117t-72 91zM1664 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37 [...]
+<glyph unicode="&#xf0e5;" horiz-adv-x="1792" d="M896 1152q-204 0 -381.5 -69.5t-282 -187.5t-104.5 -255q0 -112 71.5 -213.5t201.5 -175.5l87 -50l-27 -96q-24 -91 -70 -172q152 63 275 171l43 38l57 -6q69 -8 130 -8q204 0 381.5 69.5t282 187.5t104.5 255t-104.5 255t-282 187.5t-381.5 69.5zM1792 640 q0 -174 -120 -321.5t-326 -233t-450 -85.5q-70 0 -145 8q-198 -175 -460 -242q-49 -14 -114 -22h-5q-15 0 -27 10.5t-16 27.5v1q-3 4 -0.5 12t2 10t4.5 9.5l6 9t7 8.5t8 9q7 8 31 34.5t34.5 38t31 39.5t32.5 51t27 59t26  [...]
+<glyph unicode="&#xf0e6;" horiz-adv-x="1792" d="M704 1152q-153 0 -286 -52t-211.5 -141t-78.5 -191q0 -82 53 -158t149 -132l97 -56l-35 -84q34 20 62 39l44 31l53 -10q78 -14 153 -14q153 0 286 52t211.5 141t78.5 191t-78.5 191t-211.5 141t-286 52zM704 1280q191 0 353.5 -68.5t256.5 -186.5t94 -257t-94 -257 t-256.5 -186.5t-353.5 -68.5q-86 0 -176 16q-124 -88 -278 -128q-36 -9 -86 -16h-3q-11 0 -20.5 8t-11.5 21q-1 3 -1 6.5t0.5 6.5t2 6l2.5 5t3.5 5.5t4 5t4.5 5t4 4.5q5 6 23 25t26 29.5t22.5 29t25 38.5t20.5 44q [...]
+<glyph unicode="&#xf0e7;" horiz-adv-x="896" d="M885 970q18 -20 7 -44l-540 -1157q-13 -25 -42 -25q-4 0 -14 2q-17 5 -25.5 19t-4.5 30l197 808l-406 -101q-4 -1 -12 -1q-18 0 -31 11q-18 15 -13 39l201 825q4 14 16 23t28 9h328q19 0 32 -12.5t13 -29.5q0 -8 -5 -18l-171 -463l396 98q8 2 12 2q19 0 34 -15z" />
+<glyph unicode="&#xf0e8;" horiz-adv-x="1792" d="M1792 288v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192h-512v-192h96q40 0 68 -28t28 -68v-320 q0 -40 -28 -68t-68 -28h-320q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h96v192q0 52 38 90t90 38h512v192h-96q-40 0 -68 28t-28 68v320q0 40 28 68t68 28h320q40 0 68 -28t28 -68v-320q0 -40 -28 -68t-68 -28h-96v-192h [...]
+<glyph unicode="&#xf0e9;" horiz-adv-x="1664" d="M896 708v-580q0 -104 -76 -180t-180 -76t-180 76t-76 180q0 26 19 45t45 19t45 -19t19 -45q0 -50 39 -89t89 -39t89 39t39 89v580q33 11 64 11t64 -11zM1664 681q0 -13 -9.5 -22.5t-22.5 -9.5q-11 0 -23 10q-49 46 -93 69t-102 23q-68 0 -128 -37t-103 -97 q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -28 -17q-18 0 -29 17q-4 6 -14.5 24t-17.5 28q-43 60 -102.5 97t-127.5 37t-127.5 -37t-102.5 -97q-7 -10 -17.5 -28t-14.5 -24q-11 -17 -29 -17q-17 0 -28 17q-4 6 -14.5 24t-17.5 2 [...]
+<glyph unicode="&#xf0ea;" horiz-adv-x="1792" d="M768 -128h896v640h-416q-40 0 -68 28t-28 68v416h-384v-1152zM1024 1312v64q0 13 -9.5 22.5t-22.5 9.5h-704q-13 0 -22.5 -9.5t-9.5 -22.5v-64q0 -13 9.5 -22.5t22.5 -9.5h704q13 0 22.5 9.5t9.5 22.5zM1280 640h299l-299 299v-299zM1792 512v-672q0 -40 -28 -68t-68 -28 h-960q-40 0 -68 28t-28 68v160h-544q-40 0 -68 28t-28 68v1344q0 40 28 68t68 28h1088q40 0 68 -28t28 -68v-328q21 -13 36 -28l408 -408q28 -28 48 -76t20 -88z" />
+<glyph unicode="&#xf0eb;" horiz-adv-x="1024" d="M736 960q0 -13 -9.5 -22.5t-22.5 -9.5t-22.5 9.5t-9.5 22.5q0 46 -54 71t-106 25q-13 0 -22.5 9.5t-9.5 22.5t9.5 22.5t22.5 9.5q50 0 99.5 -16t87 -54t37.5 -90zM896 960q0 72 -34.5 134t-90 101.5t-123 62t-136.5 22.5t-136.5 -22.5t-123 -62t-90 -101.5t-34.5 -134 q0 -101 68 -180q10 -11 30.5 -33t30.5 -33q128 -153 141 -298h228q13 145 141 298q10 11 30.5 33t30.5 33q68 79 68 180zM1024 960q0 -155 -103 -268q-45 -49 -74.5 -87t-59.5 -95.5t-34 -107.5q47 -28 47 -82q [...]
+<glyph unicode="&#xf0ec;" horiz-adv-x="1792" d="M1792 352v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-1376v-192q0 -13 -9.5 -22.5t-22.5 -9.5q-12 0 -24 10l-319 320q-9 9 -9 22q0 14 9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h1376q13 0 22.5 -9.5t9.5 -22.5zM1792 896q0 -14 -9 -23l-320 -320q-9 -9 -23 -9 q-13 0 -22.5 9.5t-9.5 22.5v192h-1376q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h1376v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23z" />
+<glyph unicode="&#xf0ed;" horiz-adv-x="1920" d="M1280 608q0 14 -9 23t-23 9h-224v352q0 13 -9.5 22.5t-22.5 9.5h-192q-13 0 -22.5 -9.5t-9.5 -22.5v-352h-224q-13 0 -22.5 -9.5t-9.5 -22.5q0 -14 9 -23l352 -352q9 -9 23 -9t23 9l351 351q10 12 10 24zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0ee;" horiz-adv-x="1920" d="M1280 672q0 14 -9 23l-352 352q-9 9 -23 9t-23 -9l-351 -351q-10 -12 -10 -24q0 -14 9 -23t23 -9h224v-352q0 -13 9.5 -22.5t22.5 -9.5h192q13 0 22.5 9.5t9.5 22.5v352h224q13 0 22.5 9.5t9.5 22.5zM1920 384q0 -159 -112.5 -271.5t-271.5 -112.5h-1088 q-185 0 -316.5 131.5t-131.5 316.5q0 130 70 240t188 165q-2 30 -2 43q0 212 150 362t362 150q156 0 285.5 -87t188.5 -231q71 62 166 62q106 0 181 -75t75 -181q0 -76 -41 -138q130 -31 213.5 -135.5t83.5 -238.5z" />
+<glyph unicode="&#xf0f0;" horiz-adv-x="1408" d="M384 192q0 -26 -19 -45t-45 -19t-45 19t-19 45t19 45t45 19t45 -19t19 -45zM1408 131q0 -121 -73 -190t-194 -69h-874q-121 0 -194 69t-73 190q0 68 5.5 131t24 138t47.5 132.5t81 103t120 60.5q-22 -52 -22 -120v-203q-58 -20 -93 -70t-35 -111q0 -80 56 -136t136 -56 t136 56t56 136q0 61 -35.5 111t-92.5 70v203q0 62 25 93q132 -104 295 -104t295 104q25 -31 25 -93v-64q-106 0 -181 -75t-75 -181v-89q-32 -29 -32 -71q0 -40 28 -68t68 -28t68 28t28 68q0 42 -32 71v89q0 52 [...]
+<glyph unicode="&#xf0f1;" horiz-adv-x="1408" d="M1280 832q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 832q0 -62 -35.5 -111t-92.5 -70v-395q0 -159 -131.5 -271.5t-316.5 -112.5t-316.5 112.5t-131.5 271.5v132q-164 20 -274 128t-110 252v512q0 26 19 45t45 19q6 0 16 -2q17 30 47 48 t65 18q53 0 90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5q-33 0 -64 18v-402q0 -106 94 -181t226 -75t226 75t94 181v402q-31 -18 -64 -18q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5q35 0 65 -18t47 - [...]
+<glyph unicode="&#xf0f2;" horiz-adv-x="1792" d="M640 1152h512v128h-512v-128zM288 1152v-1280h-64q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h64zM1408 1152v-1280h-1024v1280h128v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h128zM1792 928v-832q0 -92 -66 -158t-158 -66h-64v1280h64q92 0 158 -66 t66 -158z" />
+<glyph unicode="&#xf0f3;" horiz-adv-x="1792" d="M912 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM1728 128q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-181 75t-75 181h-448q-52 0 -90 38t-38 90q50 42 91 88t85 119.5t74.5 158.5 t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68 28t68 -28t28 -68q0 -20 -8 -39q190 -28 307 -158.5t117 -282.5q0 -139 19.5 -260t50 -206t74.5 -158.5t85 -119.5t91 -88z" />
+<glyph unicode="&#xf0f4;" horiz-adv-x="1920" d="M1664 896q0 80 -56 136t-136 56h-64v-384h64q80 0 136 56t56 136zM0 128h1792q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM1856 896q0 -159 -112.5 -271.5t-271.5 -112.5h-64v-32q0 -92 -66 -158t-158 -66h-704q-92 0 -158 66t-66 158v736q0 26 19 45 t45 19h1152q159 0 271.5 -112.5t112.5 -271.5z" />
+<glyph unicode="&#xf0f5;" horiz-adv-x="1408" d="M640 1472v-640q0 -61 -35.5 -111t-92.5 -70v-779q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v779q-57 20 -92.5 70t-35.5 111v640q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45v-416q0 -26 19 -45 t45 -19t45 19t19 45v416q0 26 19 45t45 19t45 -19t19 -45zM1408 1472v-1600q0 -52 -38 -90t-90 -38h-128q-52 0 -90 38t-38 90v512h-224q-13 0 -22.5 9.5t-9.5 22.5v800q0 132 94 226t226 94h256q26 0 45 -19t1 [...]
+<glyph unicode="&#xf0f6;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M384 736q0 14 9 23t23 9h704q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64zM1120 512q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-704q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h704zM1120 256q14 0 23 -9t9 [...]
+<glyph unicode="&#xf0f7;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22 [...]
+<glyph unicode="&#xf0f8;" horiz-adv-x="1408" d="M384 224v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5z M640 480v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h64q13 0 22.5 -9.5t9.5 -22.5zM384 736v-64q0 -13 -9.5 -22.5t-22.5 -9.5h-64q-13 0 -22.5 9.5t-9.5 22 [...]
+<glyph unicode="&#xf0f9;" horiz-adv-x="1920" d="M640 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM256 640h384v256h-158q-14 -2 -22 -9l-195 -195q-7 -12 -9 -22v-30zM1536 128q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5zM1664 800v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23  [...]
+<glyph unicode="&#xf0fa;" horiz-adv-x="1792" d="M1280 416v192q0 14 -9 23t-23 9h-224v224q0 14 -9 23t-23 9h-192q-14 0 -23 -9t-9 -23v-224h-224q-14 0 -23 -9t-9 -23v-192q0 -14 9 -23t23 -9h224v-224q0 -14 9 -23t23 -9h192q14 0 23 9t9 23v224h224q14 0 23 9t9 23zM640 1152h512v128h-512v-128zM256 1152v-1280h-32 q-92 0 -158 66t-66 158v832q0 92 66 158t158 66h32zM1440 1152v-1280h-1088v1280h160v160q0 40 28 68t68 28h576q40 0 68 -28t28 -68v-160h160zM1792 928v-832q0 -92 -66 -158t-158 -66h-32v1280h32q92 0 15 [...]
+<glyph unicode="&#xf0fb;" horiz-adv-x="1920" d="M1920 576q-1 -32 -288 -96l-352 -32l-224 -64h-64l-293 -352h69q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-96h-160h-64v32h64v416h-160l-192 -224h-96l-32 32v192h32v32h128v8l-192 24v128l192 24v8h-128v32h-32v192l32 32h96l192 -224h160v416h-64v32h64h160h96 q26 0 45 -4.5t19 -11.5t-19 -11.5t-45 -4.5h-69l293 -352h64l224 -64l352 -32q261 -58 287 -93z" />
+<glyph unicode="&#xf0fc;" horiz-adv-x="1664" d="M640 640v384h-256v-256q0 -53 37.5 -90.5t90.5 -37.5h128zM1664 192v-192h-1152v192l128 192h-128q-159 0 -271.5 112.5t-112.5 271.5v320l-64 64l32 128h480l32 128h960l32 -192l-64 -32v-800z" />
+<glyph unicode="&#xf0fd;" d="M1280 192v896q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-512v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-896q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h512v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf0fe;" d="M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf100;" horiz-adv-x="1024" d="M627 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23zM1011 160q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23z" />
+<glyph unicode="&#xf101;" horiz-adv-x="1024" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM979 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23 l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf102;" horiz-adv-x="1152" d="M1075 224q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23zM1075 608q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393 q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf103;" horiz-adv-x="1152" d="M1075 672q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23zM1075 1056q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23 t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf104;" horiz-adv-x="640" d="M627 992q0 -13 -10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf105;" horiz-adv-x="640" d="M595 576q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf106;" horiz-adv-x="1152" d="M1075 352q0 -13 -10 -23l-50 -50q-10 -10 -23 -10t-23 10l-393 393l-393 -393q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l466 -466q10 -10 10 -23z" />
+<glyph unicode="&#xf107;" horiz-adv-x="1152" d="M1075 800q0 -13 -10 -23l-466 -466q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l393 -393l393 393q10 10 23 10t23 -10l50 -50q10 -10 10 -23z" />
+<glyph unicode="&#xf108;" horiz-adv-x="1920" d="M1792 544v832q0 13 -9.5 22.5t-22.5 9.5h-1600q-13 0 -22.5 -9.5t-9.5 -22.5v-832q0 -13 9.5 -22.5t22.5 -9.5h1600q13 0 22.5 9.5t9.5 22.5zM1920 1376v-1088q0 -66 -47 -113t-113 -47h-544q0 -37 16 -77.5t32 -71t16 -43.5q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19 t-19 45q0 14 16 44t32 70t16 78h-544q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h1600q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf109;" horiz-adv-x="1920" d="M416 256q-66 0 -113 47t-47 113v704q0 66 47 113t113 47h1088q66 0 113 -47t47 -113v-704q0 -66 -47 -113t-113 -47h-1088zM384 1120v-704q0 -13 9.5 -22.5t22.5 -9.5h1088q13 0 22.5 9.5t9.5 22.5v704q0 13 -9.5 22.5t-22.5 9.5h-1088q-13 0 -22.5 -9.5t-9.5 -22.5z M1760 192h160v-96q0 -40 -47 -68t-113 -28h-1600q-66 0 -113 28t-47 68v96h160h1600zM1040 96q16 0 16 16t-16 16h-160q-16 0 -16 -16t16 -16h160z" />
+<glyph unicode="&#xf10a;" horiz-adv-x="1152" d="M640 128q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1024 288v960q0 13 -9.5 22.5t-22.5 9.5h-832q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h832q13 0 22.5 9.5t9.5 22.5zM1152 1248v-1088q0 -66 -47 -113t-113 -47h-832 q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h832q66 0 113 -47t47 -113z" />
+<glyph unicode="&#xf10b;" horiz-adv-x="768" d="M464 128q0 33 -23.5 56.5t-56.5 23.5t-56.5 -23.5t-23.5 -56.5t23.5 -56.5t56.5 -23.5t56.5 23.5t23.5 56.5zM672 288v704q0 13 -9.5 22.5t-22.5 9.5h-512q-13 0 -22.5 -9.5t-9.5 -22.5v-704q0 -13 9.5 -22.5t22.5 -9.5h512q13 0 22.5 9.5t9.5 22.5zM480 1136 q0 16 -16 16h-160q-16 0 -16 -16t16 -16h160q16 0 16 16zM768 1152v-1024q0 -52 -38 -90t-90 -38h-512q-52 0 -90 38t-38 90v1024q0 52 38 90t90 38h512q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf10c;" d="M768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103 t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf10d;" horiz-adv-x="1664" d="M768 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75 -181v-32q0 -40 28 -68t68 -28h224q80 0 136 -56t56 -136z M1664 576v-384q0 -80 -56 -136t-136 -56h-384q-80 0 -136 56t-56 136v704q0 104 40.5 198.5t109.5 163.5t163.5 109.5t198.5 40.5h64q26 0 45 -19t19 -45v-128q0 -26 -19 -45t-45 -19h-64q-106 0 -181 -75t-75  [...]
+<glyph unicode="&#xf10e;" horiz-adv-x="1664" d="M768 1216v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 56 136t136 56h384q80 0 136 -56t56 -136zM1664 1216 v-704q0 -104 -40.5 -198.5t-109.5 -163.5t-163.5 -109.5t-198.5 -40.5h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64q106 0 181 75t75 181v32q0 40 -28 68t-68 28h-224q-80 0 -136 56t-56 136v384q0 80 [...]
+<glyph unicode="&#xf110;" horiz-adv-x="1792" d="M526 142q0 -53 -37.5 -90.5t-90.5 -37.5q-52 0 -90 38t-38 90q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1024 -64q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM320 640q0 -53 -37.5 -90.5t-90.5 -37.5 t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1522 142q0 -52 -38 -90t-90 -38q-53 0 -90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM558 1138q0 -66 -47 -113t-11 [...]
+<glyph unicode="&#xf111;" d="M1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf112;" horiz-adv-x="1792" d="M1792 416q0 -166 -127 -451q-3 -7 -10.5 -24t-13.5 -30t-13 -22q-12 -17 -28 -17q-15 0 -23.5 10t-8.5 25q0 9 2.5 26.5t2.5 23.5q5 68 5 123q0 101 -17.5 181t-48.5 138.5t-80 101t-105.5 69.5t-133 42.5t-154 21.5t-175.5 6h-224v-256q0 -26 -19 -45t-45 -19t-45 19 l-512 512q-19 19 -19 45t19 45l512 512q19 19 45 19t45 -19t19 -45v-256h224q713 0 875 -403q53 -134 53 -333z" />
+<glyph unicode="&#xf113;" horiz-adv-x="1664" d="M640 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1280 320q0 -40 -12.5 -82t-43 -76t-72.5 -34t-72.5 34t-43 76t-12.5 82t12.5 82t43 76t72.5 34t72.5 -34t43 -76t12.5 -82zM1440 320 q0 120 -69 204t-187 84q-41 0 -195 -21q-71 -11 -157 -11t-157 11q-152 21 -195 21q-118 0 -187 -84t-69 -204q0 -88 32 -153.5t81 -103t122 -60t140 -29.5t149 -7h168q82 0 149 7t140 29.5t122 60t81 103t32 153.5zM16 [...]
+<glyph unicode="&#xf114;" horiz-adv-x="1664" d="M1536 224v704q0 40 -28 68t-68 28h-704q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68v-960q0 -40 28 -68t68 -28h1216q40 0 68 28t28 68zM1664 928v-704q0 -92 -66 -158t-158 -66h-1216q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320 q92 0 158 -66t66 -158v-32h672q92 0 158 -66t66 -158z" />
+<glyph unicode="&#xf115;" horiz-adv-x="1920" d="M1781 605q0 35 -53 35h-1088q-40 0 -85.5 -21.5t-71.5 -52.5l-294 -363q-18 -24 -18 -40q0 -35 53 -35h1088q40 0 86 22t71 53l294 363q18 22 18 39zM640 768h768v160q0 40 -28 68t-68 28h-576q-40 0 -68 28t-28 68v64q0 40 -28 68t-68 28h-320q-40 0 -68 -28t-28 -68 v-853l256 315q44 53 116 87.5t140 34.5zM1909 605q0 -62 -46 -120l-295 -363q-43 -53 -116 -87.5t-140 -34.5h-1088q-92 0 -158 66t-66 158v960q0 92 66 158t158 66h320q92 0 158 -66t66 -158v-32h544q92 0 158 [...]
+<glyph unicode="&#xf116;" horiz-adv-x="1792" />
+<glyph unicode="&#xf117;" horiz-adv-x="1792" />
+<glyph unicode="&#xf118;" d="M1134 461q-37 -121 -138 -195t-228 -74t-228 74t-138 195q-8 25 4 48.5t38 31.5q25 8 48.5 -4t31.5 -38q25 -80 92.5 -129.5t151.5 -49.5t151.5 49.5t92.5 129.5q8 26 32 38t49 4t37 -31.5t4 -48.5zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-2 [...]
+<glyph unicode="&#xf119;" d="M1134 307q8 -25 -4 -48.5t-37 -31.5t-49 4t-32 38q-25 80 -92.5 129.5t-151.5 49.5t-151.5 -49.5t-92.5 -129.5q-8 -26 -31.5 -38t-48.5 -4q-26 8 -38 31.5t-4 48.5q37 121 138 195t228 74t228 -74t138 -195zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248 [...]
+<glyph unicode="&#xf11a;" d="M1152 448q0 -26 -19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h640q26 0 45 -19t19 -45zM640 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1152 896q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5 t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136. [...]
+<glyph unicode="&#xf11b;" horiz-adv-x="1920" d="M832 448v128q0 14 -9 23t-23 9h-192v192q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-192h-192q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h192v-192q0 -14 9 -23t23 -9h128q14 0 23 9t9 23v192h192q14 0 23 9t9 23zM1408 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1664 640q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1920 512q0 -212 -150 -362t-362 -1 [...]
+<glyph unicode="&#xf11c;" horiz-adv-x="1920" d="M384 368v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM512 624v-96q0 -16 -16 -16h-224q-16 0 -16 16v96q0 16 16 16h224q16 0 16 -16zM384 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM1408 368v-96q0 -16 -16 -16 h-864q-16 0 -16 16v96q0 16 16 16h864q16 0 16 -16zM768 624v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16zM640 880v-96q0 -16 -16 -16h-96q-16 0 -16 16v96q0 16 16 16h96q16 0 16 -16z [...]
+<glyph unicode="&#xf11d;" horiz-adv-x="1792" d="M1664 491v616q-169 -91 -306 -91q-82 0 -145 32q-100 49 -184 76.5t-178 27.5q-173 0 -403 -127v-599q245 113 433 113q55 0 103.5 -7.5t98 -26t77 -31t82.5 -39.5l28 -14q44 -22 101 -22q120 0 293 92zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q0 -14 -9 -23t-23 -9 h-64q-14 0 -23 9t-9 23v1266q-29 17 -46.5 46t-17.5 64q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1792 1216v-763q0 -39 -35 -57q-10 -5 -17 -9q-218 -116 -369 -116q-88 0 -158 35l-28 14q-64 33 -9 [...]
+<glyph unicode="&#xf11e;" horiz-adv-x="1792" d="M832 536v192q-181 -16 -384 -117v-185q205 96 384 110zM832 954v197q-172 -8 -384 -126v-189q215 111 384 118zM1664 491v184q-235 -116 -384 -71v224q-20 6 -39 15q-5 3 -33 17t-34.5 17t-31.5 15t-34.5 15.5t-32.5 13t-36 12.5t-35 8.5t-39.5 7.5t-39.5 4t-44 2 q-23 0 -49 -3v-222h19q102 0 192.5 -29t197.5 -82q19 -9 39 -15v-188q42 -17 91 -17q120 0 293 92zM1664 918v189q-169 -91 -306 -91q-45 0 -78 8v-196q148 -42 384 90zM320 1280q0 -35 -17.5 -64t-46.5 -46v-1266q [...]
+<glyph unicode="&#xf120;" horiz-adv-x="1664" d="M585 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10t23 -10l466 -466q10 -10 10 -23t-10 -23zM1664 96v-64q0 -14 -9 -23t-23 -9h-960q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h960q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf121;" horiz-adv-x="1920" d="M617 137l-50 -50q-10 -10 -23 -10t-23 10l-466 466q-10 10 -10 23t10 23l466 466q10 10 23 10t23 -10l50 -50q10 -10 10 -23t-10 -23l-393 -393l393 -393q10 -10 10 -23t-10 -23zM1208 1204l-373 -1291q-4 -13 -15.5 -19.5t-23.5 -2.5l-62 17q-13 4 -19.5 15.5t-2.5 24.5 l373 1291q4 13 15.5 19.5t23.5 2.5l62 -17q13 -4 19.5 -15.5t2.5 -24.5zM1865 553l-466 -466q-10 -10 -23 -10t-23 10l-50 50q-10 10 -10 23t10 23l393 393l-393 393q-10 10 -10 23t10 23l50 50q10 10 23 10 [...]
+<glyph unicode="&#xf122;" horiz-adv-x="1792" d="M640 454v-70q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-69l-397 -398q-19 -19 -19 -45t19 -45zM1792 416q0 -58 -17 -133.5t-38.5 -138t-48 -125t-40.5 -90.5l-20 -40q-8 -17 -28 -17q-6 0 -9 1 q-25 8 -23 34q43 400 -106 565q-64 71 -170.5 110.5t-267.5 52.5v-251q0 -42 -39 -59q-13 -5 -25 -5q-27 0 -45 19l-512 512q-19 19 -19 45t19 45l512 512q29 31 70 14q39 -17 39 -59v-262q411 -28 599 -221q169 - [...]
+<glyph unicode="&#xf123;" horiz-adv-x="1664" d="M1186 579l257 250l-356 52l-66 10l-30 60l-159 322v-963l59 -31l318 -168l-60 355l-12 66zM1638 841l-363 -354l86 -500q5 -33 -6 -51.5t-34 -18.5q-17 0 -40 12l-449 236l-449 -236q-23 -12 -40 -12q-23 0 -34 18.5t-6 51.5l86 500l-364 354q-32 32 -23 59.5t54 34.5 l502 73l225 455q20 41 49 41q28 0 49 -41l225 -455l502 -73q45 -7 54 -34.5t-24 -59.5z" />
+<glyph unicode="&#xf124;" horiz-adv-x="1408" d="M1401 1187l-640 -1280q-17 -35 -57 -35q-5 0 -15 2q-22 5 -35.5 22.5t-13.5 39.5v576h-576q-22 0 -39.5 13.5t-22.5 35.5t4 42t29 30l1280 640q13 7 29 7q27 0 45 -19q15 -14 18.5 -34.5t-6.5 -39.5z" />
+<glyph unicode="&#xf125;" horiz-adv-x="1664" d="M557 256h595v595zM512 301l595 595h-595v-595zM1664 224v-192q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v224h-864q-14 0 -23 9t-9 23v864h-224q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h224v224q0 14 9 23t23 9h192q14 0 23 -9t9 -23 v-224h851l246 247q10 9 23 9t23 -9q9 -10 9 -23t-9 -23l-247 -246v-851h224q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf126;" horiz-adv-x="1024" d="M288 64q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM288 1216q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM928 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1024 1088q0 -52 -26 -96.5t-70 -69.5 q-2 -287 -226 -414q-68 -38 -203 -81q-128 -40 -169.5 -71t-41.5 -100v-26q44 -25 70 -69.5t26 -96.5q0 -80 -56 -136t-136 -56t-136 56t-56 136q0 52 26 96.5t70 69.5v820q-44 25 -70 69.5t-26 96.5q0 80 56 13 [...]
+<glyph unicode="&#xf127;" horiz-adv-x="1664" d="M439 265l-256 -256q-10 -9 -23 -9q-12 0 -23 9q-9 10 -9 23t9 23l256 256q10 9 23 9t23 -9q9 -10 9 -23t-9 -23zM608 224v-320q0 -14 -9 -23t-23 -9t-23 9t-9 23v320q0 14 9 23t23 9t23 -9t9 -23zM384 448q0 -14 -9 -23t-23 -9h-320q-14 0 -23 9t-9 23t9 23t23 9h320 q14 0 23 -9t9 -23zM1648 320q0 -120 -85 -203l-147 -146q-83 -83 -203 -83q-121 0 -204 85l-334 335q-21 21 -42 56l239 18l273 -274q27 -27 68 -27.5t68 26.5l147 146q28 28 28 67q0 40 -28 68l-274 275l18 239 [...]
+<glyph unicode="&#xf128;" horiz-adv-x="1024" d="M704 280v-240q0 -16 -12 -28t-28 -12h-240q-16 0 -28 12t-12 28v240q0 16 12 28t28 12h240q16 0 28 -12t12 -28zM1020 880q0 -54 -15.5 -101t-35 -76.5t-55 -59.5t-57.5 -43.5t-61 -35.5q-41 -23 -68.5 -65t-27.5 -67q0 -17 -12 -32.5t-28 -15.5h-240q-15 0 -25.5 18.5 t-10.5 37.5v45q0 83 65 156.5t143 108.5q59 27 84 56t25 76q0 42 -46.5 74t-107.5 32q-65 0 -108 -29q-35 -25 -107 -115q-13 -16 -31 -16q-12 0 -25 8l-164 125q-13 10 -15.5 25t5.5 28q160 266 464 266q80 0 [...]
+<glyph unicode="&#xf129;" horiz-adv-x="640" d="M640 192v-128q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h64v384h-64q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h384q26 0 45 -19t19 -45v-576h64q26 0 45 -19t19 -45zM512 1344v-192q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v192 q0 26 19 45t45 19h256q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf12a;" horiz-adv-x="640" d="M512 288v-224q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v224q0 26 19 45t45 19h256q26 0 45 -19t19 -45zM542 1344l-28 -768q-1 -26 -20.5 -45t-45.5 -19h-256q-26 0 -45.5 19t-20.5 45l-28 768q-1 26 17.5 45t44.5 19h320q26 0 44.5 -19t17.5 -45z" />
+<glyph unicode="&#xf12b;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1534 846v-206h-514l-3 27 q-4 28 -4 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q83 65 188 65q110 0 178 -59.5t68 -158.5q0 -56 -24.5 -103t-62 -76.5t-81.5 -58.5t- [...]
+<glyph unicode="&#xf12c;" d="M897 167v-167h-248l-159 252l-24 42q-8 9 -11 21h-3l-9 -21q-10 -20 -25 -44l-155 -250h-258v167h128l197 291l-185 272h-137v168h276l139 -228q2 -4 23 -42q8 -9 11 -21h3q3 9 11 21l25 42l140 228h257v-168h-125l-184 -267l204 -296h109zM1536 -50v-206h-514l-4 27 q-3 45 -3 46q0 64 26 117t65 86.5t84 65t84 54.5t65 54t26 64q0 38 -29.5 62.5t-70.5 24.5q-51 0 -97 -39q-14 -11 -36 -38l-105 92q26 37 63 66q80 65 188 65q110 0 178 -59.5t68 -158.5q0 -66 -34.5 -118.5t-84 -86t-99.5 -62.5t- [...]
+<glyph unicode="&#xf12d;" horiz-adv-x="1920" d="M896 128l336 384h-768l-336 -384h768zM1909 1205q15 -34 9.5 -71.5t-30.5 -65.5l-896 -1024q-38 -44 -96 -44h-768q-38 0 -69.5 20.5t-47.5 54.5q-15 34 -9.5 71.5t30.5 65.5l896 1024q38 44 96 44h768q38 0 69.5 -20.5t47.5 -54.5z" />
+<glyph unicode="&#xf12e;" horiz-adv-x="1664" d="M1664 438q0 -81 -44.5 -135t-123.5 -54q-41 0 -77.5 17.5t-59 38t-56.5 38t-71 17.5q-110 0 -110 -124q0 -39 16 -115t15 -115v-5q-22 0 -33 -1q-34 -3 -97.5 -11.5t-115.5 -13.5t-98 -5q-61 0 -103 26.5t-42 83.5q0 37 17.5 71t38 56.5t38 59t17.5 77.5q0 79 -54 123.5 t-135 44.5q-84 0 -143 -45.5t-59 -127.5q0 -43 15 -83t33.5 -64.5t33.5 -53t15 -50.5q0 -45 -46 -89q-37 -35 -117 -35q-95 0 -245 24q-9 2 -27.5 4t-27.5 4l-13 2q-1 0 -3 1q-2 0 -2 1v1024q2 -1 17.5 -3.5t [...]
+<glyph unicode="&#xf130;" horiz-adv-x="1152" d="M1152 832v-128q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-217 24 -364.5 187.5t-147.5 384.5v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -185 131.5 -316.5t316.5 -131.5 t316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45zM896 1216v-512q0 -132 -94 -226t-226 -94t-226 94t-94 226v512q0 132 94 226t226 94t226 -94t94 -226z" />
+<glyph unicode="&#xf131;" horiz-adv-x="1408" d="M271 591l-101 -101q-42 103 -42 214v128q0 26 19 45t45 19t45 -19t19 -45v-128q0 -53 15 -113zM1385 1193l-361 -361v-128q0 -132 -94 -226t-226 -94q-55 0 -109 19l-96 -96q97 -51 205 -51q185 0 316.5 131.5t131.5 316.5v128q0 26 19 45t45 19t45 -19t19 -45v-128 q0 -221 -147.5 -384.5t-364.5 -187.5v-132h256q26 0 45 -19t19 -45t-19 -45t-45 -19h-640q-26 0 -45 19t-19 45t19 45t45 19h256v132q-125 13 -235 81l-254 -254q-10 -10 -23 -10t-23 10l-82 82q-10 10 -10 23t10 [...]
+<glyph unicode="&#xf132;" horiz-adv-x="1280" d="M1088 576v640h-448v-1137q119 63 213 137q235 184 235 360zM1280 1344v-768q0 -86 -33.5 -170.5t-83 -150t-118 -127.5t-126.5 -103t-121 -77.5t-89.5 -49.5t-42.5 -20q-12 -6 -26 -6t-26 6q-16 7 -42.5 20t-89.5 49.5t-121 77.5t-126.5 103t-118 127.5t-83 150 t-33.5 170.5v768q0 26 19 45t45 19h1152q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf133;" horiz-adv-x="1664" d="M128 -128h1408v1024h-1408v-1024zM512 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1280 1088v288q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-288q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1664 1152v-1280 q0 -52 -38 -90t-90 -38h-1408q-52 0 -90 38t-38 90v1280q0 52 38 90t90 38h128v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h384v96q0 66 47 113t113 47h64q66 0 113 -47t47 -113v-96h128q52 0 90 -38t38 -90z" />
+<glyph unicode="&#xf134;" horiz-adv-x="1408" d="M512 1344q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1408 1376v-320q0 -16 -12 -25q-8 -7 -20 -7q-4 0 -7 1l-448 96q-11 2 -18 11t-7 20h-256v-102q111 -23 183.5 -111t72.5 -203v-800q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v800 q0 106 62.5 190.5t161.5 114.5v111h-32q-59 0 -115 -23.5t-91.5 -53t-66 -66.5t-40.5 -53.5t-14 -24.5q-17 -35 -57 -35q-16 0 -29 7q-23 12 -31.5 37t3.5 49q5 10 14.5 26t37.5 53.5t60.5 70t85 67t108.5 52.5q-2 [...]
+<glyph unicode="&#xf135;" horiz-adv-x="1664" d="M1440 1088q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1664 1376q0 -249 -75.5 -430.5t-253.5 -360.5q-81 -80 -195 -176l-20 -379q-2 -16 -16 -26l-384 -224q-7 -4 -16 -4q-12 0 -23 9l-64 64q-13 14 -8 32l85 276l-281 281l-276 -85q-3 -1 -9 -1 q-14 0 -23 9l-64 64q-17 19 -5 39l224 384q10 14 26 16l379 20q96 114 176 195q188 187 358 258t431 71q14 0 24 -9.5t10 -22.5z" />
+<glyph unicode="&#xf136;" horiz-adv-x="1792" d="M1745 763l-164 -763h-334l178 832q13 56 -15 88q-27 33 -83 33h-169l-204 -953h-334l204 953h-286l-204 -953h-334l204 953l-153 327h1276q101 0 189.5 -40.5t147.5 -113.5q60 -73 81 -168.5t0 -194.5z" />
+<glyph unicode="&#xf137;" d="M909 141l102 102q19 19 19 45t-19 45l-307 307l307 307q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf138;" d="M717 141l454 454q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l307 -307l-307 -307q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf139;" d="M1165 397l102 102q19 19 19 45t-19 45l-454 454q-19 19 -45 19t-45 -19l-454 -454q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l307 307l307 -307q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13a;" d="M813 237l454 454q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-307 -307l-307 307q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l454 -454q19 -19 45 -19t45 19zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5 t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf13b;" horiz-adv-x="1408" d="M1130 939l16 175h-884l47 -534h612l-22 -228l-197 -53l-196 53l-13 140h-175l22 -278l362 -100h4v1l359 99l50 544h-644l-15 181h674zM0 1408h1408l-128 -1438l-578 -162l-574 162z" />
+<glyph unicode="&#xf13c;" horiz-adv-x="1792" d="M275 1408h1505l-266 -1333l-804 -267l-698 267l71 356h297l-29 -147l422 -161l486 161l68 339h-1208l58 297h1209l38 191h-1208z" />
+<glyph unicode="&#xf13d;" horiz-adv-x="1792" d="M960 1280q0 26 -19 45t-45 19t-45 -19t-19 -45t19 -45t45 -19t45 19t19 45zM1792 352v-352q0 -22 -20 -30q-8 -2 -12 -2q-13 0 -23 9l-93 93q-119 -143 -318.5 -226.5t-429.5 -83.5t-429.5 83.5t-318.5 226.5l-93 -93q-9 -9 -23 -9q-4 0 -12 2q-20 8 -20 30v352 q0 14 9 23t23 9h352q22 0 30 -20q8 -19 -7 -35l-100 -100q67 -91 189.5 -153.5t271.5 -82.5v647h-192q-26 0 -45 19t-19 45v128q0 26 19 45t45 19h192v163q-58 34 -93 92.5t-35 128.5q0 106 75 181t181 75t181 -75t75 [...]
+<glyph unicode="&#xf13e;" horiz-adv-x="1152" d="M1056 768q40 0 68 -28t28 -68v-576q0 -40 -28 -68t-68 -28h-960q-40 0 -68 28t-28 68v576q0 40 28 68t68 28h32v320q0 185 131.5 316.5t316.5 131.5t316.5 -131.5t131.5 -316.5q0 -26 -19 -45t-45 -19h-64q-26 0 -45 19t-19 45q0 106 -75 181t-181 75t-181 -75t-75 -181 v-320h736z" />
+<glyph unicode="&#xf140;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM1152 640q0 159 -112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5t112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5zM1280 640q0 -212 -150 -362t-362 -150t-362 150 t-150 362t150 362t362 150t362 -150t150 -362zM1408 640q0 130 -51 248.5t-136.5 204t-204 136.5t-248.5 51t-248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 2 [...]
+<glyph unicode="&#xf141;" horiz-adv-x="1408" d="M384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM896 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM1408 800v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf142;" horiz-adv-x="384" d="M384 288v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 800v-192q0 -40 -28 -68t-68 -28h-192q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68zM384 1312v-192q0 -40 -28 -68t-68 -28h-192 q-40 0 -68 28t-28 68v192q0 40 28 68t68 28h192q40 0 68 -28t28 -68z" />
+<glyph unicode="&#xf143;" d="M512 256q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM863 162q-13 232 -177 396t-396 177q-14 1 -24 -9t-10 -23v-128q0 -13 8.5 -22t21.5 -10q154 -11 264 -121t121 -264q1 -13 10 -21.5t22 -8.5h128q13 0 23 10 t9 24zM1247 161q-5 154 -56 297.5t-139.5 260t-205 205t-260 139.5t-297.5 56q-14 1 -23 -9q-10 -10 -10 -23v-128q0 -13 9 -22t22 -10q204 -7 378 -111.5t278.5 -278.5t111.5 -378q1 -13 10 -22t22 -9h128q13 0 23 10q11 9 9 23z [...]
+<glyph unicode="&#xf144;" d="M768 1408q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1152 585q32 18 32 55t-32 55l-544 320q-31 19 -64 1q-32 -19 -32 -56v-640q0 -37 32 -56 q16 -8 32 -8q17 0 32 9z" />
+<glyph unicode="&#xf145;" horiz-adv-x="1792" d="M1024 1084l316 -316l-572 -572l-316 316zM813 105l618 618q19 19 19 45t-19 45l-362 362q-18 18 -45 18t-45 -18l-618 -618q-19 -19 -19 -45t19 -45l362 -362q18 -18 45 -18t45 18zM1702 742l-907 -908q-37 -37 -90.5 -37t-90.5 37l-126 126q56 56 56 136t-56 136 t-136 56t-136 -56l-125 126q-37 37 -37 90.5t37 90.5l907 906q37 37 90.5 37t90.5 -37l125 -125q-56 -56 -56 -136t56 -136t136 -56t136 56l126 -125q37 -37 37 -90.5t-37 -90.5z" />
+<glyph unicode="&#xf146;" d="M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf147;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h832q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5 t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf148;" horiz-adv-x="1024" d="M1018 933q-18 -37 -58 -37h-192v-864q0 -14 -9 -23t-23 -9h-704q-21 0 -29 18q-8 20 4 35l160 192q9 11 25 11h320v640h-192q-40 0 -58 37q-17 37 9 68l320 384q18 22 49 22t49 -22l320 -384q27 -32 9 -68z" />
+<glyph unicode="&#xf149;" horiz-adv-x="1024" d="M32 1280h704q13 0 22.5 -9.5t9.5 -23.5v-863h192q40 0 58 -37t-9 -69l-320 -384q-18 -22 -49 -22t-49 22l-320 384q-26 31 -9 69q18 37 58 37h192v640h-320q-14 0 -25 11l-160 192q-13 14 -4 34q9 19 29 19z" />
+<glyph unicode="&#xf14a;" d="M685 237l614 614q19 19 19 45t-19 45l-102 102q-19 19 -45 19t-45 -19l-467 -467l-211 211q-19 19 -45 19t-45 -19l-102 -102q-19 -19 -19 -45t19 -45l358 -358q19 -19 45 -19t45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5 t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14b;" d="M404 428l152 -152l-52 -52h-56v96h-96v56zM818 818q14 -13 -3 -30l-291 -291q-17 -17 -30 -3q-14 13 3 30l291 291q17 17 30 3zM544 128l544 544l-288 288l-544 -544v-288h288zM1152 736l92 92q28 28 28 68t-28 68l-152 152q-28 28 -68 28t-68 -28l-92 -92zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14c;" d="M1280 608v480q0 26 -19 45t-45 19h-480q-42 0 -59 -39q-17 -41 14 -70l144 -144l-534 -534q-19 -19 -19 -45t19 -45l102 -102q19 -19 45 -19t45 19l534 534l144 -144q18 -19 45 -19q12 0 25 5q39 17 39 59zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960 q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14d;" d="M1005 435l352 352q19 19 19 45t-19 45l-352 352q-30 31 -69 14q-40 -17 -40 -59v-160q-119 0 -216 -19.5t-162.5 -51t-114 -79t-76.5 -95.5t-44.5 -109t-21.5 -111.5t-5 -110.5q0 -181 167 -404q10 -12 25 -12q7 0 13 3q22 9 19 33q-44 354 62 473q46 52 130 75.5 t224 23.5v-160q0 -42 40 -59q12 -5 24 -5q26 0 45 19zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf14e;" d="M640 448l256 128l-256 128v-256zM1024 1039v-542l-512 -256v542zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf150;" d="M1145 861q18 -35 -5 -66l-320 -448q-19 -27 -52 -27t-52 27l-320 448q-23 31 -5 66q17 35 57 35h640q40 0 57 -35zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120 v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf151;" d="M1145 419q-17 -35 -57 -35h-640q-40 0 -57 35q-18 35 5 66l320 448q19 27 52 27t52 -27l320 -448q23 -31 5 -66zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf152;" d="M1088 640q0 -33 -27 -52l-448 -320q-31 -23 -66 -5q-35 17 -35 57v640q0 40 35 57q35 18 66 -5l448 -320q27 -19 27 -52zM1280 160v960q0 14 -9 23t-23 9h-960q-14 0 -23 -9t-9 -23v-960q0 -14 9 -23t23 -9h960q14 0 23 9t9 23zM1536 1120v-960q0 -119 -84.5 -203.5 t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf153;" horiz-adv-x="1024" d="M976 229l35 -159q3 -12 -3 -22.5t-17 -14.5l-5 -1q-4 -2 -10.5 -3.5t-16 -4.5t-21.5 -5.5t-25.5 -5t-30 -5t-33.5 -4.5t-36.5 -3t-38.5 -1q-234 0 -409 130.5t-238 351.5h-95q-13 0 -22.5 9.5t-9.5 22.5v113q0 13 9.5 22.5t22.5 9.5h66q-2 57 1 105h-67q-14 0 -23 9 t-9 23v114q0 14 9 23t23 9h98q67 210 243.5 338t400.5 128q102 0 194 -23q11 -3 20 -15q6 -11 3 -24l-43 -159q-3 -13 -14 -19.5t-24 -2.5l-4 1q-4 1 -11.5 2.5l-17.5 3.5t-22.5 3.5t-26 3t-29 2.5t-29.5 1q-126  [...]
+<glyph unicode="&#xf154;" horiz-adv-x="1024" d="M1020 399v-367q0 -14 -9 -23t-23 -9h-956q-14 0 -23 9t-9 23v150q0 13 9.5 22.5t22.5 9.5h97v383h-95q-14 0 -23 9.5t-9 22.5v131q0 14 9 23t23 9h95v223q0 171 123.5 282t314.5 111q185 0 335 -125q9 -8 10 -20.5t-7 -22.5l-103 -127q-9 -11 -22 -12q-13 -2 -23 7 q-5 5 -26 19t-69 32t-93 18q-85 0 -137 -47t-52 -123v-215h305q13 0 22.5 -9t9.5 -23v-131q0 -13 -9.5 -22.5t-22.5 -9.5h-305v-379h414v181q0 13 9 22.5t23 9.5h162q14 0 23 -9.5t9 -22.5z" />
+<glyph unicode="&#xf155;" horiz-adv-x="1024" d="M978 351q0 -153 -99.5 -263.5t-258.5 -136.5v-175q0 -14 -9 -23t-23 -9h-135q-13 0 -22.5 9.5t-9.5 22.5v175q-66 9 -127.5 31t-101.5 44.5t-74 48t-46.5 37.5t-17.5 18q-17 21 -2 41l103 135q7 10 23 12q15 2 24 -9l2 -2q113 -99 243 -125q37 -8 74 -8q81 0 142.5 43 t61.5 122q0 28 -15 53t-33.5 42t-58.5 37.5t-66 32t-80 32.5q-39 16 -61.5 25t-61.5 26.5t-62.5 31t-56.5 35.5t-53.5 42.5t-43.5 49t-35.5 58t-21 66.5t-8.5 78q0 138 98 242t255 134v180q0 13 9.5 22.5t22.5  [...]
+<glyph unicode="&#xf156;" horiz-adv-x="898" d="M898 1066v-102q0 -14 -9 -23t-23 -9h-168q-23 -144 -129 -234t-276 -110q167 -178 459 -536q14 -16 4 -34q-8 -18 -29 -18h-195q-16 0 -25 12q-306 367 -498 571q-9 9 -9 22v127q0 13 9.5 22.5t22.5 9.5h112q132 0 212.5 43t102.5 125h-427q-14 0 -23 9t-9 23v102 q0 14 9 23t23 9h413q-57 113 -268 113h-145q-13 0 -22.5 9.5t-9.5 22.5v133q0 14 9 23t23 9h832q14 0 23 -9t9 -23v-102q0 -14 -9 -23t-23 -9h-233q47 -61 64 -144h171q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf157;" horiz-adv-x="1027" d="M603 0h-172q-13 0 -22.5 9t-9.5 23v330h-288q-13 0 -22.5 9t-9.5 23v103q0 13 9.5 22.5t22.5 9.5h288v85h-288q-13 0 -22.5 9t-9.5 23v104q0 13 9.5 22.5t22.5 9.5h214l-321 578q-8 16 0 32q10 16 28 16h194q19 0 29 -18l215 -425q19 -38 56 -125q10 24 30.5 68t27.5 61 l191 420q8 19 29 19h191q17 0 27 -16q9 -14 1 -31l-313 -579h215q13 0 22.5 -9.5t9.5 -22.5v-104q0 -14 -9.5 -23t-22.5 -9h-290v-85h290q13 0 22.5 -9.5t9.5 -22.5v-103q0 -14 -9.5 -23t-22.5 -9h-290v-330q [...]
+<glyph unicode="&#xf158;" horiz-adv-x="1280" d="M1043 971q0 100 -65 162t-171 62h-320v-448h320q106 0 171 62t65 162zM1280 971q0 -193 -126.5 -315t-326.5 -122h-340v-118h505q14 0 23 -9t9 -23v-128q0 -14 -9 -23t-23 -9h-505v-192q0 -14 -9.5 -23t-22.5 -9h-167q-14 0 -23 9t-9 23v192h-224q-14 0 -23 9t-9 23v128 q0 14 9 23t23 9h224v118h-224q-14 0 -23 9t-9 23v149q0 13 9 22.5t23 9.5h224v629q0 14 9 23t23 9h539q200 0 326.5 -122t126.5 -315z" />
+<glyph unicode="&#xf159;" horiz-adv-x="1792" d="M514 341l81 299h-159l75 -300q1 -1 1 -3t1 -3q0 1 0.5 3.5t0.5 3.5zM630 768l35 128h-292l32 -128h225zM822 768h139l-35 128h-70zM1271 340l78 300h-162l81 -299q0 -1 0.5 -3.5t1.5 -3.5q0 1 0.5 3t0.5 3zM1382 768l33 128h-297l34 -128h230zM1792 736v-64q0 -14 -9 -23 t-23 -9h-213l-164 -616q-7 -24 -31 -24h-159q-24 0 -31 24l-166 616h-209l-167 -616q-7 -24 -31 -24h-159q-11 0 -19.5 7t-10.5 17l-160 616h-208q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h175l-33 128h-142q-1 [...]
+<glyph unicode="&#xf15a;" horiz-adv-x="1280" d="M1167 896q18 -182 -131 -258q117 -28 175 -103t45 -214q-7 -71 -32.5 -125t-64.5 -89t-97 -58.5t-121.5 -34.5t-145.5 -15v-255h-154v251q-80 0 -122 1v-252h-154v255q-18 0 -54 0.5t-55 0.5h-200l31 183h111q50 0 58 51v402h16q-6 1 -16 1v287q-13 68 -89 68h-111v164 l212 -1q64 0 97 1v252h154v-247q82 2 122 2v245h154v-252q79 -7 140 -22.5t113 -45t82.5 -78t36.5 -114.5zM952 351q0 36 -15 64t-37 46t-57.5 30.5t-65.5 18.5t-74 9t-69 3t-64.5 -1t-47.5 -1v-338q8 0 37 -0 [...]
+<glyph unicode="&#xf15b;" d="M1024 1024v472q22 -14 36 -28l408 -408q14 -14 28 -36h-472zM896 992q0 -40 28 -68t68 -28h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544z" />
+<glyph unicode="&#xf15c;" d="M1468 1060q14 -14 28 -36h-472v472q22 -14 36 -28zM992 896h544v-1056q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h800v-544q0 -40 28 -68t68 -28zM1152 160v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704 q14 0 23 9t9 23zM1152 416v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23zM1152 672v64q0 14 -9 23t-23 9h-704q-14 0 -23 -9t-9 -23v-64q0 -14 9 -23t23 -9h704q14 0 23 9t9 23z" />
+<glyph unicode="&#xf15d;" horiz-adv-x="1664" d="M1191 1128h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1572 -23 v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567v-89l-369 -530q-6 -8 -21 -26l-11 -11v-2l14 2q9 2 30 2h248v119h121zM1661 874v-106h-288v106h75l- [...]
+<glyph unicode="&#xf15e;" horiz-adv-x="1664" d="M1191 104h177l-72 218l-12 47q-2 16 -2 20h-4l-3 -20q0 -1 -3.5 -18t-7.5 -29zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1661 -150 v-106h-288v106h75l-47 144h-243l-47 -144h75v-106h-287v106h70l230 662h162l230 -662h70zM1572 1001v-233h-584v90l369 529q12 18 21 27l11 9v3q-2 0 -6.5 -0.5t-7.5 -0.5q-12 -3 -30 -3h-232v-115h-120v229h567 [...]
+<glyph unicode="&#xf160;" horiz-adv-x="1792" d="M736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23zM1792 -32v-192q0 -14 -9 -23t-23 -9h-832q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h832 q14 0 23 -9t9 -23zM1600 480v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14 0 23 -9t9 -23zM1408 992v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14  [...]
+<glyph unicode="&#xf161;" horiz-adv-x="1792" d="M1216 -32v-192q0 -14 -9 -23t-23 -9h-256q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h256q14 0 23 -9t9 -23zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192 q14 0 23 -9t9 -23zM1408 480v-192q0 -14 -9 -23t-23 -9h-448q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h448q14 0 23 -9t9 -23zM1600 992v-192q0 -14 -9 -23t-23 -9h-640q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h640q14  [...]
+<glyph unicode="&#xf162;" d="M1346 223q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9t9 -23 zM1486 165q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -42 15l39 113q15 -7 31 -11q37 -13 75 -13q84 0 134.5 58.5t66.5 145.5h-2q-21 -23 -61.5 -37t-84.5 -14q-106 0 -173 71.5t-67 [...]
+<glyph unicode="&#xf163;" d="M1346 1247q0 63 -44 116t-103 53q-52 0 -83 -37t-31 -94t36.5 -95t104.5 -38q50 0 85 27t35 68zM736 96q0 -12 -10 -24l-319 -319q-10 -9 -23 -9q-12 0 -23 9l-320 320q-15 16 -7 35q8 20 30 20h192v1376q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1376h192q14 0 23 -9 t9 -23zM1456 -142v-114h-469v114h167v432q0 7 0.5 19t0.5 17v16h-2l-7 -12q-8 -13 -26 -31l-62 -58l-82 86l192 185h123v-654h165zM1486 1189q0 -62 -13 -121.5t-41 -114t-68 -95.5t-98.5 -65.5t-127.5 -24.5q-62 0 -108 16q-24 8 -4 [...]
+<glyph unicode="&#xf164;" horiz-adv-x="1664" d="M256 192q0 26 -19 45t-45 19q-27 0 -45.5 -19t-18.5 -45q0 -27 18.5 -45.5t45.5 -18.5q26 0 45 18.5t19 45.5zM416 704v-640q0 -26 -19 -45t-45 -19h-288q-26 0 -45 19t-19 45v640q0 26 19 45t45 19h288q26 0 45 -19t19 -45zM1600 704q0 -86 -55 -149q15 -44 15 -76 q3 -76 -43 -137q17 -56 0 -117q-15 -57 -54 -94q9 -112 -49 -181q-64 -76 -197 -78h-36h-76h-17q-66 0 -144 15.5t-121.5 29t-120.5 39.5q-123 43 -158 44q-26 1 -45 19.5t-19 44.5v641q0 25 18 43.5t43 20.5q24  [...]
+<glyph unicode="&#xf165;" horiz-adv-x="1664" d="M256 960q0 -26 -19 -45t-45 -19q-27 0 -45.5 19t-18.5 45q0 27 18.5 45.5t45.5 18.5q26 0 45 -18.5t19 -45.5zM416 448v640q0 26 -19 45t-45 19h-288q-26 0 -45 -19t-19 -45v-640q0 -26 19 -45t45 -19h288q26 0 45 19t19 45zM1545 597q55 -61 55 -149q-1 -78 -57.5 -135 t-134.5 -57h-277q4 -14 8 -24t11 -22t10 -18q18 -37 27 -57t19 -58.5t10 -76.5q0 -24 -0.5 -39t-5 -45t-12 -50t-24 -45t-40 -40.5t-60 -26t-82.5 -10.5q-26 0 -45 19q-20 20 -34 50t-19.5 52t-12.5 61q-9 42 [...]
+<glyph unicode="&#xf166;" d="M919 233v157q0 50 -29 50q-17 0 -33 -16v-224q16 -16 33 -16q29 0 29 49zM1103 355h66v34q0 51 -33 51t-33 -51v-34zM532 621v-70h-80v-423h-74v423h-78v70h232zM733 495v-367h-67v40q-39 -45 -76 -45q-33 0 -42 28q-6 16 -6 54v290h66v-270q0 -24 1 -26q1 -15 15 -15 q20 0 42 31v280h67zM985 384v-146q0 -52 -7 -73q-12 -42 -53 -42q-35 0 -68 41v-36h-67v493h67v-161q32 40 68 40q41 0 53 -42q7 -21 7 -74zM1236 255v-9q0 -29 -2 -43q-3 -22 -15 -40q-27 -40 -80 -40q-52 0 -81 38q-21 27 -21 86 [...]
+<glyph unicode="&#xf167;" d="M971 292v-211q0 -67 -39 -67q-23 0 -45 22v301q22 22 45 22q39 0 39 -67zM1309 291v-46h-90v46q0 68 45 68t45 -68zM343 509h107v94h-312v-94h105v-569h100v569zM631 -60h89v494h-89v-378q-30 -42 -57 -42q-18 0 -21 21q-1 3 -1 35v364h-89v-391q0 -49 8 -73 q12 -37 58 -37q48 0 102 61v-54zM1060 88v197q0 73 -9 99q-17 56 -71 56q-50 0 -93 -54v217h-89v-663h89v48q45 -55 93 -55q54 0 71 55q9 27 9 100zM1398 98v13h-91q0 -51 -2 -61q-7 -36 -40 -36q-46 0 -46 69v87h179v103q0 79 -27 116q-39  [...]
+<glyph unicode="&#xf168;" horiz-adv-x="1408" d="M597 869q-10 -18 -257 -456q-27 -46 -65 -46h-239q-21 0 -31 17t0 36l253 448q1 0 0 1l-161 279q-12 22 -1 37q9 15 32 15h239q40 0 66 -45zM1403 1511q11 -16 0 -37l-528 -934v-1l336 -615q11 -20 1 -37q-10 -15 -32 -15h-239q-42 0 -66 45l-339 622q18 32 531 942 q25 45 64 45h241q22 0 31 -15z" />
+<glyph unicode="&#xf169;" d="M685 771q0 1 -126 222q-21 34 -52 34h-184q-18 0 -26 -11q-7 -12 1 -29l125 -216v-1l-196 -346q-9 -14 0 -28q8 -13 24 -13h185q31 0 50 36zM1309 1268q-7 12 -24 12h-187q-30 0 -49 -35l-411 -729q1 -2 262 -481q20 -35 52 -35h184q18 0 25 12q8 13 -1 28l-260 476v1 l409 723q8 16 0 28zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf16a;" horiz-adv-x="1792" d="M1280 640q0 37 -30 54l-512 320q-31 20 -65 2q-33 -18 -33 -56v-640q0 -38 33 -56q16 -8 31 -8q20 0 34 10l512 320q30 17 30 54zM1792 640q0 -96 -1 -150t-8.5 -136.5t-22.5 -147.5q-16 -73 -69 -123t-124 -58q-222 -25 -671 -25t-671 25q-71 8 -124.5 58t-69.5 123 q-14 65 -21.5 147.5t-8.5 136.5t-1 150t1 150t8.5 136.5t22.5 147.5q16 73 69 123t124 58q222 25 671 25t671 -25q71 -8 124.5 -58t69.5 -123q14 -65 21.5 -147.5t8.5 -136.5t1 -150z" />
+<glyph unicode="&#xf16b;" horiz-adv-x="1792" d="M402 829l494 -305l-342 -285l-490 319zM1388 274v-108l-490 -293v-1l-1 1l-1 -1v1l-489 293v108l147 -96l342 284v2l1 -1l1 1v-2l343 -284zM554 1418l342 -285l-494 -304l-338 270zM1390 829l338 -271l-489 -319l-343 285zM1239 1418l489 -319l-338 -270l-494 304z" />
+<glyph unicode="&#xf16c;" horiz-adv-x="1408" d="M928 135v-151l-707 -1v151zM1169 481v-701l-1 -35v-1h-1132l-35 1h-1v736h121v-618h928v618h120zM241 393l704 -65l-13 -150l-705 65zM309 709l683 -183l-39 -146l-683 183zM472 1058l609 -360l-77 -130l-609 360zM832 1389l398 -585l-124 -85l-399 584zM1285 1536 l121 -697l-149 -26l-121 697z" />
+<glyph unicode="&#xf16d;" d="M1362 110v648h-135q20 -63 20 -131q0 -126 -64 -232.5t-174 -168.5t-240 -62q-197 0 -337 135.5t-140 327.5q0 68 20 131h-141v-648q0 -26 17.5 -43.5t43.5 -17.5h1069q25 0 43 17.5t18 43.5zM1078 643q0 124 -90.5 211.5t-218.5 87.5q-127 0 -217.5 -87.5t-90.5 -211.5 t90.5 -211.5t217.5 -87.5q128 0 218.5 87.5t90.5 211.5zM1362 1003v165q0 28 -20 48.5t-49 20.5h-174q-29 0 -49 -20.5t-20 -48.5v-165q0 -29 20 -49t49 -20h174q29 0 49 20t20 49zM1536 1211v-1142q0 -81 -58 -139t-139 -58h-11 [...]
+<glyph unicode="&#xf16e;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM698 640q0 88 -62 150t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150zM1262 640q0 88 -62 150 t-150 62t-150 -62t-62 -150t62 -150t150 -62t150 62t62 150z" />
+<glyph unicode="&#xf170;" d="M768 914l201 -306h-402zM1133 384h94l-459 691l-459 -691h94l104 160h522zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf171;" horiz-adv-x="1408" d="M815 677q8 -63 -50.5 -101t-111.5 -6q-39 17 -53.5 58t-0.5 82t52 58q36 18 72.5 12t64 -35.5t27.5 -67.5zM926 698q-14 107 -113 164t-197 13q-63 -28 -100.5 -88.5t-34.5 -129.5q4 -91 77.5 -155t165.5 -56q91 8 152 84t50 168zM1165 1240q-20 27 -56 44.5t-58 22 t-71 12.5q-291 47 -566 -2q-43 -7 -66 -12t-55 -22t-50 -43q30 -28 76 -45.5t73.5 -22t87.5 -11.5q228 -29 448 -1q63 8 89.5 12t72.5 21.5t75 46.5zM1222 205q-8 -26 -15.5 -76.5t-14 -84t-28.5 -70t-58 -56.5q- [...]
+<glyph unicode="&#xf172;" d="M848 666q0 43 -41 66t-77 1q-43 -20 -42.5 -72.5t43.5 -70.5q39 -23 81 4t36 72zM928 682q8 -66 -36 -121t-110 -61t-119 40t-56 113q-2 49 25.5 93t72.5 64q70 31 141.5 -10t81.5 -118zM1100 1073q-20 -21 -53.5 -34t-53 -16t-63.5 -8q-155 -20 -324 0q-44 6 -63 9.5 t-52.5 16t-54.5 32.5q13 19 36 31t40 15.5t47 8.5q198 35 408 1q33 -5 51 -8.5t43 -16t39 -31.5zM1142 327q0 7 5.5 26.5t3 32t-17.5 16.5q-161 -106 -365 -106t-366 106l-12 -6l-5 -12q26 -154 41 -210q47 -81 204 -108q249 -46 4 [...]
+<glyph unicode="&#xf173;" horiz-adv-x="1024" d="M944 207l80 -237q-23 -35 -111 -66t-177 -32q-104 -2 -190.5 26t-142.5 74t-95 106t-55.5 120t-16.5 118v544h-168v215q72 26 129 69.5t91 90t58 102t34 99t15 88.5q1 5 4.5 8.5t7.5 3.5h244v-424h333v-252h-334v-518q0 -30 6.5 -56t22.5 -52.5t49.5 -41.5t81.5 -14 q78 2 134 29z" />
+<glyph unicode="&#xf174;" d="M1136 75l-62 183q-44 -22 -103 -22q-36 -1 -62 10.5t-38.5 31.5t-17.5 40.5t-5 43.5v398h257v194h-256v326h-188q-8 0 -9 -10q-5 -44 -17.5 -87t-39 -95t-77 -95t-118.5 -68v-165h130v-418q0 -57 21.5 -115t65 -111t121 -85.5t176.5 -30.5q69 1 136.5 25t85.5 50z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf175;" horiz-adv-x="768" d="M765 237q8 -19 -5 -35l-350 -384q-10 -10 -23 -10q-14 0 -24 10l-355 384q-13 16 -5 35q9 19 29 19h224v1248q0 14 9 23t23 9h192q14 0 23 -9t9 -23v-1248h224q21 0 29 -19z" />
+<glyph unicode="&#xf176;" horiz-adv-x="768" d="M765 1043q-9 -19 -29 -19h-224v-1248q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v1248h-224q-21 0 -29 19t5 35l350 384q10 10 23 10q14 0 24 -10l355 -384q13 -16 5 -35z" />
+<glyph unicode="&#xf177;" horiz-adv-x="1792" d="M1792 736v-192q0 -14 -9 -23t-23 -9h-1248v-224q0 -21 -19 -29t-35 5l-384 350q-10 10 -10 23q0 14 10 24l384 354q16 14 35 6q19 -9 19 -29v-224h1248q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf178;" horiz-adv-x="1792" d="M1728 643q0 -14 -10 -24l-384 -354q-16 -14 -35 -6q-19 9 -19 29v224h-1248q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h1248v224q0 21 19 29t35 -5l384 -350q10 -10 10 -23z" />
+<glyph unicode="&#xf179;" horiz-adv-x="1408" d="M1393 321q-39 -125 -123 -250q-129 -196 -257 -196q-49 0 -140 32q-86 32 -151 32q-61 0 -142 -33q-81 -34 -132 -34q-152 0 -301 259q-147 261 -147 503q0 228 113 374q112 144 284 144q72 0 177 -30q104 -30 138 -30q45 0 143 34q102 34 173 34q119 0 213 -65 q52 -36 104 -100q-79 -67 -114 -118q-65 -94 -65 -207q0 -124 69 -223t158 -126zM1017 1494q0 -61 -29 -136q-30 -75 -93 -138q-54 -54 -108 -72q-37 -11 -104 -17q3 149 78 257q74 107 250 148q1 -3 2.5 -11t2.5 -11 [...]
+<glyph unicode="&#xf17a;" horiz-adv-x="1664" d="M682 530v-651l-682 94v557h682zM682 1273v-659h-682v565zM1664 530v-786l-907 125v661h907zM1664 1408v-794h-907v669z" />
+<glyph unicode="&#xf17b;" horiz-adv-x="1408" d="M493 1053q16 0 27.5 11.5t11.5 27.5t-11.5 27.5t-27.5 11.5t-27 -11.5t-11 -27.5t11 -27.5t27 -11.5zM915 1053q16 0 27 11.5t11 27.5t-11 27.5t-27 11.5t-27.5 -11.5t-11.5 -27.5t11.5 -27.5t27.5 -11.5zM103 869q42 0 72 -30t30 -72v-430q0 -43 -29.5 -73t-72.5 -30 t-73 30t-30 73v430q0 42 30 72t73 30zM1163 850v-666q0 -46 -32 -78t-77 -32h-75v-227q0 -43 -30 -73t-73 -30t-73 30t-30 73v227h-138v-227q0 -43 -30 -73t-73 -30q-42 0 -72 30t-30 73l-1 227h-74q-46 0 -78  [...]
+<glyph unicode="&#xf17c;" d="M663 1125q-11 -1 -15.5 -10.5t-8.5 -9.5q-5 -1 -5 5q0 12 19 15h10zM750 1111q-4 -1 -11.5 6.5t-17.5 4.5q24 11 32 -2q3 -6 -3 -9zM399 684q-4 1 -6 -3t-4.5 -12.5t-5.5 -13.5t-10 -13q-7 -10 -1 -12q4 -1 12.5 7t12.5 18q1 3 2 7t2 6t1.5 4.5t0.5 4v3t-1 2.5t-3 2z M1254 325q0 18 -55 42q4 15 7.5 27.5t5 26t3 21.5t0.5 22.5t-1 19.5t-3.5 22t-4 20.5t-5 25t-5.5 26.5q-10 48 -47 103t-72 75q24 -20 57 -83q87 -162 54 -278q-11 -40 -50 -42q-31 -4 -38.5 18.5t-8 83.5t-11.5 107q-9 39 -19.5 69 [...]
+<glyph unicode="&#xf17d;" d="M1024 36q-42 241 -140 498h-2l-2 -1q-16 -6 -43 -16.5t-101 -49t-137 -82t-131 -114.5t-103 -148l-15 11q184 -150 418 -150q132 0 256 52zM839 643q-21 49 -53 111q-311 -93 -673 -93q-1 -7 -1 -21q0 -124 44 -236.5t124 -201.5q50 89 123.5 166.5t142.5 124.5t130.5 81 t99.5 48l37 13q4 1 13 3.5t13 4.5zM732 855q-120 213 -244 378q-138 -65 -234 -186t-128 -272q302 0 606 80zM1416 536q-210 60 -409 29q87 -239 128 -469q111 75 185 189.5t96 250.5zM611 1277q-1 0 -2 -1q1 1 2 1zM1201 1132q [...]
+<glyph unicode="&#xf17e;" d="M1173 473q0 50 -19.5 91.5t-48.5 68.5t-73 49t-82.5 34t-87.5 23l-104 24q-30 7 -44 10.5t-35 11.5t-30 16t-16.5 21t-7.5 30q0 77 144 77q43 0 77 -12t54 -28.5t38 -33.5t40 -29t48 -12q47 0 75.5 32t28.5 77q0 55 -56 99.5t-142 67.5t-182 23q-68 0 -132 -15.5 t-119.5 -47t-89 -87t-33.5 -128.5q0 -61 19 -106.5t56 -75.5t80 -48.5t103 -32.5l146 -36q90 -22 112 -36q32 -20 32 -60q0 -39 -40 -64.5t-105 -25.5q-51 0 -91.5 16t-65 38.5t-45.5 45t-46 38.5t-54 16q-50 0 -75.5 -30t-25.5 -75q0 - [...]
+<glyph unicode="&#xf180;" horiz-adv-x="1280" d="M1000 1102l37 194q5 23 -9 40t-35 17h-712q-23 0 -38.5 -17t-15.5 -37v-1101q0 -7 6 -1l291 352q23 26 38 33.5t48 7.5h239q22 0 37 14.5t18 29.5q24 130 37 191q4 21 -11.5 40t-36.5 19h-294q-29 0 -48 19t-19 48v42q0 29 19 47.5t48 18.5h346q18 0 35 13.5t20 29.5z M1227 1324q-15 -73 -53.5 -266.5t-69.5 -350t-35 -173.5q-6 -22 -9 -32.5t-14 -32.5t-24.5 -33t-38.5 -21t-58 -10h-271q-13 0 -22 -10q-8 -9 -426 -494q-22 -25 -58.5 -28.5t-48.5 5.5q-55 22 -55 98v1410q0 5 [...]
+<glyph unicode="&#xf181;" d="M704 192v1024q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-1024q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1376 576v640q0 14 -9 23t-23 9h-480q-14 0 -23 -9t-9 -23v-640q0 -14 9 -23t23 -9h480q14 0 23 9t9 23zM1536 1344v-1408q0 -26 -19 -45t-45 -19h-1408 q-26 0 -45 19t-19 45v1408q0 26 19 45t45 19h1408q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf182;" horiz-adv-x="1280" d="M1280 480q0 -40 -28 -68t-68 -28q-51 0 -80 43l-227 341h-45v-132l247 -411q9 -15 9 -33q0 -26 -19 -45t-45 -19h-192v-272q0 -46 -33 -79t-79 -33h-160q-46 0 -79 33t-33 79v272h-192q-26 0 -45 19t-19 45q0 18 9 33l247 411v132h-45l-227 -341q-29 -43 -80 -43 q-40 0 -68 28t-28 68q0 29 16 53l256 384q73 107 176 107h384q103 0 176 -107l256 -384q16 -24 16 -53zM864 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65. [...]
+<glyph unicode="&#xf183;" horiz-adv-x="1024" d="M1024 832v-416q0 -40 -28 -68t-68 -28t-68 28t-28 68v352h-64v-912q0 -46 -33 -79t-79 -33t-79 33t-33 79v464h-64v-464q0 -46 -33 -79t-79 -33t-79 33t-33 79v912h-64v-352q0 -40 -28 -68t-68 -28t-68 28t-28 68v416q0 80 56 136t136 56h640q80 0 136 -56t56 -136z M736 1280q0 -93 -65.5 -158.5t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf184;" d="M773 234l350 473q16 22 24.5 59t-6 85t-61.5 79q-40 26 -83 25.5t-73.5 -17.5t-54.5 -45q-36 -40 -96 -40q-59 0 -95 40q-24 28 -54.5 45t-73.5 17.5t-84 -25.5q-46 -31 -60.5 -79t-6 -85t24.5 -59zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf185;" horiz-adv-x="1792" d="M1472 640q0 117 -45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5t223.5 45.5t184 123t123 184t45.5 223.5zM1748 363q-4 -15 -20 -20l-292 -96v-306q0 -16 -13 -26q-15 -10 -29 -4 l-292 94l-180 -248q-10 -13 -26 -13t-26 13l-180 248l-292 -94q-14 -6 -29 4q-13 10 -13 26v306l-292 96q-16 5 -20 20q-5 17 4 29l180 248l-180 248q-9 13 -4 29q4 15 20 20l292 96v306q0 16 13 26q15 10 2 [...]
+<glyph unicode="&#xf186;" d="M1262 233q-54 -9 -110 -9q-182 0 -337 90t-245 245t-90 337q0 192 104 357q-201 -60 -328.5 -229t-127.5 -384q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51q144 0 273.5 61.5t220.5 171.5zM1465 318q-94 -203 -283.5 -324.5t-413.5 -121.5q-156 0 -298 61 t-245 164t-164 245t-61 298q0 153 57.5 292.5t156 241.5t235.5 164.5t290 68.5q44 2 61 -39q18 -41 -15 -72q-86 -78 -131.5 -181.5t-45.5 -218.5q0 -148 73 -273t198 -198t273 -73q118 0 228 51q41 18 72 -13q14 -14 17.5 -34t-4.5 -38z" />
+<glyph unicode="&#xf187;" horiz-adv-x="1792" d="M1088 704q0 26 -19 45t-45 19h-256q-26 0 -45 -19t-19 -45t19 -45t45 -19h256q26 0 45 19t19 45zM1664 896v-960q0 -26 -19 -45t-45 -19h-1408q-26 0 -45 19t-19 45v960q0 26 19 45t45 19h1408q26 0 45 -19t19 -45zM1728 1344v-256q0 -26 -19 -45t-45 -19h-1536 q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h1536q26 0 45 -19t19 -45z" />
+<glyph unicode="&#xf188;" horiz-adv-x="1664" d="M1632 576q0 -26 -19 -45t-45 -19h-224q0 -171 -67 -290l208 -209q19 -19 19 -45t-19 -45q-18 -19 -45 -19t-45 19l-198 197q-5 -5 -15 -13t-42 -28.5t-65 -36.5t-82 -29t-97 -13v896h-128v-896q-51 0 -101.5 13.5t-87 33t-66 39t-43.5 32.5l-15 14l-183 -207 q-20 -21 -48 -21q-24 0 -43 16q-19 18 -20.5 44.5t15.5 46.5l202 227q-58 114 -58 274h-224q-26 0 -45 19t-19 45t19 45t45 19h224v294l-173 173q-19 19 -19 45t19 45t45 19t45 -19l173 -173h844l173 173q19 19 45 19t45 [...]
+<glyph unicode="&#xf189;" horiz-adv-x="1920" d="M1917 1016q23 -64 -150 -294q-24 -32 -65 -85q-78 -100 -90 -131q-17 -41 14 -81q17 -21 81 -82h1l1 -1l1 -1l2 -2q141 -131 191 -221q3 -5 6.5 -12.5t7 -26.5t-0.5 -34t-25 -27.5t-59 -12.5l-256 -4q-24 -5 -56 5t-52 22l-20 12q-30 21 -70 64t-68.5 77.5t-61 58 t-56.5 15.5q-3 -1 -8 -3.5t-17 -14.5t-21.5 -29.5t-17 -52t-6.5 -77.5q0 -15 -3.5 -27.5t-7.5 -18.5l-4 -5q-18 -19 -53 -22h-115q-71 -4 -146 16.5t-131.5 53t-103 66t-70.5 57.5l-25 24q-10 10 -27.5 30t-71.5 91 [...]
+<glyph unicode="&#xf18a;" horiz-adv-x="1792" d="M675 252q21 34 11 69t-45 50q-34 14 -73 1t-60 -46q-22 -34 -13 -68.5t43 -50.5t74.5 -2.5t62.5 47.5zM769 373q8 13 3.5 26.5t-17.5 18.5q-14 5 -28.5 -0.5t-21.5 -18.5q-17 -31 13 -45q14 -5 29 0.5t22 18.5zM943 266q-45 -102 -158 -150t-224 -12 q-107 34 -147.5 126.5t6.5 187.5q47 93 151.5 139t210.5 19q111 -29 158.5 -119.5t2.5 -190.5zM1255 426q-9 96 -89 170t-208.5 109t-274.5 21q-223 -23 -369.5 -141.5t-132.5 -264.5q9 -96 89 -170t208.5 -109t274.5 -21q223 23 [...]
+<glyph unicode="&#xf18b;" d="M1133 -34q-171 -94 -368 -94q-196 0 -367 94q138 87 235.5 211t131.5 268q35 -144 132.5 -268t235.5 -211zM638 1394v-485q0 -252 -126.5 -459.5t-330.5 -306.5q-181 215 -181 495q0 187 83.5 349.5t229.5 269.5t325 137zM1536 638q0 -280 -181 -495 q-204 99 -330.5 306.5t-126.5 459.5v485q179 -30 325 -137t229.5 -269.5t83.5 -349.5z" />
+<glyph unicode="&#xf18c;" horiz-adv-x="1408" d="M1402 433q-32 -80 -76 -138t-91 -88.5t-99 -46.5t-101.5 -14.5t-96.5 8.5t-86.5 22t-69.5 27.5t-46 22.5l-17 10q-113 -228 -289.5 -359.5t-384.5 -132.5q-19 0 -32 13t-13 32t13 31.5t32 12.5q173 1 322.5 107.5t251.5 294.5q-36 -14 -72 -23t-83 -13t-91 2.5t-93 28.5 t-92 59t-84.5 100t-74.5 146q114 47 214 57t167.5 -7.5t124.5 -56.5t88.5 -77t56.5 -82q53 131 79 291q-7 -1 -18 -2.5t-46.5 -2.5t-69.5 0.5t-81.5 10t-88.5 23t-84 42.5t-75 65t-54.5 94.5t-28.5 127.5q70  [...]
+<glyph unicode="&#xf18d;" horiz-adv-x="1280" d="M1259 283v-66q0 -85 -57.5 -144.5t-138.5 -59.5h-57l-260 -269v269h-529q-81 0 -138.5 59.5t-57.5 144.5v66h1238zM1259 609v-255h-1238v255h1238zM1259 937v-255h-1238v255h1238zM1259 1077v-67h-1238v67q0 84 57.5 143.5t138.5 59.5h846q81 0 138.5 -59.5t57.5 -143.5z " />
+<glyph unicode="&#xf18e;" d="M1152 640q0 -14 -9 -23l-320 -320q-9 -9 -23 -9q-13 0 -22.5 9.5t-9.5 22.5v192h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v192q0 14 9 23t23 9q12 0 24 -10l319 -319q9 -9 9 -23zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf190;" d="M1152 736v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-192q0 -14 -9 -23t-23 -9q-12 0 -24 10l-319 319q-9 9 -9 23t9 23l320 320q9 9 23 9q13 0 22.5 -9.5t9.5 -22.5v-192h352q13 0 22.5 -9.5t9.5 -22.5zM1312 640q0 148 -73 273t-198 198t-273 73t-273 -73t-198 -198 t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf191;" d="M1024 960v-640q0 -26 -19 -45t-45 -19q-20 0 -37 12l-448 320q-27 19 -27 52t27 52l448 320q17 12 37 12q26 0 45 -19t19 -45zM1280 160v960q0 13 -9.5 22.5t-22.5 9.5h-960q-13 0 -22.5 -9.5t-9.5 -22.5v-960q0 -13 9.5 -22.5t22.5 -9.5h960q13 0 22.5 9.5t9.5 22.5z M1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf192;" d="M1024 640q0 -106 -75 -181t-181 -75t-181 75t-75 181t75 181t181 75t181 -75t75 -181zM768 1184q-148 0 -273 -73t-198 -198t-73 -273t73 -273t198 -198t273 -73t273 73t198 198t73 273t-73 273t-198 198t-273 73zM1536 640q0 -209 -103 -385.5t-279.5 -279.5 t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf193;" horiz-adv-x="1664" d="M1023 349l102 -204q-58 -179 -210 -290t-339 -111q-156 0 -288.5 77.5t-210 210t-77.5 288.5q0 181 104.5 330t274.5 211l17 -131q-122 -54 -195 -165.5t-73 -244.5q0 -185 131.5 -316.5t316.5 -131.5q126 0 232.5 65t165 175.5t49.5 236.5zM1571 249l58 -114l-256 -128 q-13 -7 -29 -7q-40 0 -57 35l-239 477h-472q-24 0 -42.5 16.5t-21.5 40.5l-96 779q-2 16 6 42q14 51 57 82.5t97 31.5q66 0 113 -47t47 -113q0 -69 -52 -117.5t-120 -41.5l37 -289h423v-128h-407l16 -128h455 [...]
+<glyph unicode="&#xf194;" d="M1254 899q16 85 -21 132q-52 65 -187 45q-17 -3 -41 -12.5t-57.5 -30.5t-64.5 -48.5t-59.5 -70t-44.5 -91.5q80 7 113.5 -16t26.5 -99q-5 -52 -52 -143q-43 -78 -71 -99q-44 -32 -87 14q-23 24 -37.5 64.5t-19 73t-10 84t-8.5 71.5q-23 129 -34 164q-12 37 -35.5 69 t-50.5 40q-57 16 -127 -25q-54 -32 -136.5 -106t-122.5 -102v-7q16 -8 25.5 -26t21.5 -20q21 -3 54.5 8.5t58 10.5t41.5 -30q11 -18 18.5 -38.5t15 -48t12.5 -40.5q17 -46 53 -187q36 -146 57 -197q42 -99 103 -125q43 -12 85 -1.5t7 [...]
+<glyph unicode="&#xf195;" horiz-adv-x="1152" d="M1152 704q0 -191 -94.5 -353t-256.5 -256.5t-353 -94.5h-160q-14 0 -23 9t-9 23v611l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v93l-215 -66q-3 -1 -9 -1q-10 0 -19 6q-13 10 -13 26v128q0 23 23 31l233 71v250q0 14 9 23t23 9h160 q14 0 23 -9t9 -23v-181l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-93l375 116q15 5 28 -5t13 -26v-128q0 -23 -23 -31l-393 -121v-487q188 13 318 151t130 328q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf196;" horiz-adv-x="1408" d="M1152 736v-64q0 -14 -9 -23t-23 -9h-352v-352q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v352h-352q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h352v352q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-352h352q14 0 23 -9t9 -23zM1280 288v832q0 66 -47 113t-113 47h-832 q-66 0 -113 -47t-47 -113v-832q0 -66 47 -113t113 -47h832q66 0 113 47t47 113zM1408 1120v-832q0 -119 -84.5 -203.5t-203.5 -84.5h-832q-119 0 -203.5 84.5t-84.5 203.5v832q0 119 84.5 203.5t203.5 84.5h832q119 0 20 [...]
+<glyph unicode="&#xf197;" horiz-adv-x="2176" d="M620 416q-110 -64 -268 -64h-128v64h-64q-13 0 -22.5 23.5t-9.5 56.5q0 24 7 49q-58 2 -96.5 10.5t-38.5 20.5t38.5 20.5t96.5 10.5q-7 25 -7 49q0 33 9.5 56.5t22.5 23.5h64v64h128q158 0 268 -64h1113q42 -7 106.5 -18t80.5 -14q89 -15 150 -40.5t83.5 -47.5t22.5 -40 t-22.5 -40t-83.5 -47.5t-150 -40.5q-16 -3 -80.5 -14t-106.5 -18h-1113zM1739 668q53 -36 53 -92t-53 -92l81 -30q68 48 68 122t-68 122zM625 400h1015q-217 -38 -456 -80q-57 0 -113 -24t-83 -48l-28 -24l-2 [...]
+<glyph unicode="&#xf198;" horiz-adv-x="1664" d="M1519 760q62 0 103.5 -40.5t41.5 -101.5q0 -97 -93 -130l-172 -59l56 -167q7 -21 7 -47q0 -59 -42 -102t-101 -43q-47 0 -85.5 27t-53.5 72l-55 165l-310 -106l55 -164q8 -24 8 -47q0 -59 -42 -102t-102 -43q-47 0 -85 27t-53 72l-55 163l-153 -53q-29 -9 -50 -9 q-61 0 -101.5 40t-40.5 101q0 47 27.5 85t71.5 53l156 53l-105 313l-156 -54q-26 -8 -48 -8q-60 0 -101 40.5t-41 100.5q0 47 27.5 85t71.5 53l157 53l-53 159q-8 24 -8 47q0 60 42 102.5t102 42.5q47 0 85 -27t53 - [...]
+<glyph unicode="&#xf199;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM1280 352v436q-31 -35 -64 -55q-34 -22 -132.5 -85t-151.5 -99q-98 -69 -164 -69v0v0q-66 0 -164 69 q-46 32 -141.5 92.5t-142.5 92.5q-12 8 -33 27t-31 27v-436q0 -40 28 -68t68 -28h832q40 0 68 28t28 68zM1280 925q0 41 -27.5 70t-68.5 29h-832q-40 0 -68 -28t-28 -68q0 -37 30.5 -76.5t67.5 -64.5q47 -32 137.5 -89t129.5 -83q3 -2 [...]
+<glyph unicode="&#xf19a;" horiz-adv-x="1792" d="M127 640q0 163 67 313l367 -1005q-196 95 -315 281t-119 411zM1415 679q0 -19 -2.5 -38.5t-10 -49.5t-11.5 -44t-17.5 -59t-17.5 -58l-76 -256l-278 826q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-75 1 -202 10q-12 1 -20.5 -5t-11.5 -15t-1.5 -18.5t9 -16.5 t19.5 -8l80 -8l120 -328l-168 -504l-280 832q46 3 88 8q19 2 26 18.5t-2.5 31t-28.5 13.5l-205 -10q-7 0 -23 0.5t-26 0.5q105 160 274.5 253.5t367.5 93.5q147 0 280.5 -53t238.5 -149h-10q-55 0 -92 -40.5 [...]
+<glyph unicode="&#xf19b;" horiz-adv-x="1792" d="M1086 1536v-1536l-272 -128q-228 20 -414 102t-293 208.5t-107 272.5q0 140 100.5 263.5t275 205.5t391.5 108v-172q-217 -38 -356.5 -150t-139.5 -255q0 -152 154.5 -267t388.5 -145v1360zM1755 954l37 -390l-525 114l147 83q-119 70 -280 99v172q277 -33 481 -157z" />
+<glyph unicode="&#xf19c;" horiz-adv-x="2048" d="M960 1536l960 -384v-128h-128q0 -26 -20.5 -45t-48.5 -19h-1526q-28 0 -48.5 19t-20.5 45h-128v128zM256 896h256v-768h128v768h256v-768h128v768h256v-768h128v768h256v-768h59q28 0 48.5 -19t20.5 -45v-64h-1664v64q0 26 20.5 45t48.5 19h59v768zM1851 -64 q28 0 48.5 -19t20.5 -45v-128h-1920v128q0 26 20.5 45t48.5 19h1782z" />
+<glyph unicode="&#xf19d;" horiz-adv-x="2304" d="M1774 700l18 -316q4 -69 -82 -128t-235 -93.5t-323 -34.5t-323 34.5t-235 93.5t-82 128l18 316l574 -181q22 -7 48 -7t48 7zM2304 1024q0 -23 -22 -31l-1120 -352q-4 -1 -10 -1t-10 1l-652 206q-43 -34 -71 -111.5t-34 -178.5q63 -36 63 -109q0 -69 -58 -107l58 -433 q2 -14 -8 -25q-9 -11 -24 -11h-192q-15 0 -24 11q-10 11 -8 25l58 433q-58 38 -58 107q0 73 65 111q11 207 98 330l-333 104q-22 8 -22 31t22 31l1120 352q4 1 10 1t10 -1l1120 -352q22 -8 22 -31z" />
+<glyph unicode="&#xf19e;" d="M859 579l13 -707q-62 11 -105 11q-41 0 -105 -11l13 707q-40 69 -168.5 295.5t-216.5 374.5t-181 287q58 -15 108 -15q43 0 111 15q63 -111 133.5 -229.5t167 -276.5t138.5 -227q37 61 109.5 177.5t117.5 190t105 176t107 189.5q54 -14 107 -14q56 0 114 14v0 q-28 -39 -60 -88.5t-49.5 -78.5t-56.5 -96t-49 -84q-146 -248 -353 -610z" />
+<glyph unicode="&#xf1a0;" horiz-adv-x="1280" d="M981 197q0 25 -7 49t-14.5 42t-27 41.5t-29.5 35t-38.5 34.5t-36.5 29t-41.5 30t-36.5 26q-16 2 -49 2q-53 0 -104.5 -7t-107 -25t-97 -46t-68.5 -74.5t-27 -105.5q0 -56 23.5 -102t61 -75.5t87 -50t100 -29t101.5 -8.5q58 0 111.5 13t99 39t73 73t27.5 109zM864 1055 q0 59 -17 125.5t-48 129t-84 103.5t-117 41q-42 0 -82.5 -19.5t-66.5 -52.5q-46 -59 -46 -160q0 -46 10 -97.5t31.5 -103t52 -92.5t75 -67t96.5 -26q37 0 77.5 16.5t65.5 43.5q53 56 53 159zM752 1536h417l-137 [...]
+<glyph unicode="&#xf1a1;" horiz-adv-x="2304" d="M1509 107q0 -14 -12 -29q-52 -59 -147.5 -83t-196.5 -24q-252 0 -346 107q-12 15 -12 29q0 17 12 29.5t29 12.5q15 0 30 -12q58 -49 125.5 -66t159.5 -17t160 17t127 66q15 12 30 12q17 0 29 -12.5t12 -29.5zM978 498q0 -61 -43 -104t-104 -43q-60 0 -104.5 43.5 t-44.5 103.5q0 61 44 105t105 44t104 -44t43 -105zM1622 498q0 -61 -43 -104t-104 -43q-60 0 -104.5 43.5t-44.5 103.5q0 61 44 105t105 44t104 -44t43 -105zM415 793q-39 27 -88 27q-66 0 -113 -47t-47 -113q0 -72  [...]
+<glyph unicode="&#xf1a2;" d="M950 393q7 7 17.5 7t17.5 -7t7 -18t-7 -18q-65 -64 -208 -64h-1h-1q-143 0 -207 64q-8 7 -8 18t8 18q7 7 17.5 7t17.5 -7q49 -51 172 -51h1h1q122 0 173 51zM671 613q0 -37 -26 -64t-63 -27t-63 27t-26 64t26 63t63 26t63 -26t26 -63zM1214 1049q-29 0 -50 21t-21 50 q0 30 21 51t50 21q30 0 51 -21t21 -51q0 -29 -21 -50t-51 -21zM1216 1408q132 0 226 -94t94 -227v-894q0 -133 -94 -227t-226 -94h-896q-132 0 -226 94t-94 227v894q0 133 94 227t226 94h896zM1321 596q35 14 57 45.5t22 70.5q0 51  [...]
+<glyph unicode="&#xf1a3;" d="M866 697l90 27v62q0 79 -58 135t-138 56t-138 -55.5t-58 -134.5v-283q0 -20 -14 -33.5t-33 -13.5t-32.5 13.5t-13.5 33.5v120h-151v-122q0 -82 57.5 -139t139.5 -57q81 0 138.5 56.5t57.5 136.5v280q0 19 13.5 33t33.5 14q19 0 32.5 -14t13.5 -33v-54zM1199 502v122h-150 v-126q0 -20 -13.5 -33.5t-33.5 -13.5q-19 0 -32.5 14t-13.5 33v123l-90 -26l-60 28v-123q0 -80 58 -137t139 -57t138.5 57t57.5 139zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385 [...]
+<glyph unicode="&#xf1a4;" horiz-adv-x="1920" d="M1062 824v118q0 42 -30 72t-72 30t-72 -30t-30 -72v-612q0 -175 -126 -299t-303 -124q-178 0 -303.5 125.5t-125.5 303.5v266h328v-262q0 -43 30 -72.5t72 -29.5t72 29.5t30 72.5v620q0 171 126.5 292t301.5 121q176 0 302 -122t126 -294v-136l-195 -58zM1592 602h328 v-266q0 -178 -125.5 -303.5t-303.5 -125.5q-177 0 -303 124.5t-126 300.5v268l131 -61l195 58v-270q0 -42 30 -71.5t72 -29.5t72 29.5t30 71.5v275z" />
+<glyph unicode="&#xf1a5;" d="M1472 160v480h-704v704h-480q-93 0 -158.5 -65.5t-65.5 -158.5v-480h704v-704h480q93 0 158.5 65.5t65.5 158.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z" />
+<glyph unicode="&#xf1a6;" horiz-adv-x="2048" d="M328 1254h204v-983h-532v697h328v286zM328 435v369h-123v-369h123zM614 968v-697h205v697h-205zM614 1254v-204h205v204h-205zM901 968h533v-942h-533v163h328v82h-328v697zM1229 435v369h-123v-369h123zM1516 968h532v-942h-532v163h327v82h-327v697zM1843 435v369h-123 v-369h123z" />
+<glyph unicode="&#xf1a7;" d="M1046 516q0 -64 -38 -109t-91 -45q-43 0 -70 15v277q28 17 70 17q53 0 91 -45.5t38 -109.5zM703 944q0 -64 -38 -109.5t-91 -45.5q-43 0 -70 15v277q28 17 70 17q53 0 91 -45t38 -109zM1265 513q0 134 -88 229t-213 95q-20 0 -39 -3q-23 -78 -78 -136q-87 -95 -211 -101 v-636l211 41v206q51 -19 117 -19q125 0 213 95t88 229zM922 940q0 134 -88.5 229t-213.5 95q-74 0 -141 -36h-186v-840l211 41v206q55 -19 116 -19q125 0 213.5 95t88.5 229zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h- [...]
+<glyph unicode="&#xf1a8;" horiz-adv-x="2038" d="M1222 607q75 3 143.5 -20.5t118 -58.5t101 -94.5t84 -108t75.5 -120.5q33 -56 78.5 -109t75.5 -80.5t99 -88.5q-48 -30 -108.5 -57.5t-138.5 -59t-114 -47.5q-44 37 -74 115t-43.5 164.5t-33 180.5t-42.5 168.5t-72.5 123t-122.5 48.5l-10 -2l-6 -4q4 -5 13 -14 q6 -5 28 -23.5t25.5 -22t19 -18t18 -20.5t11.5 -21t10.5 -27.5t4.5 -31t4 -40.5l1 -33q1 -26 -2.5 -57.5t-7.5 -52t-12.5 -58.5t-11.5 -53q-35 1 -101 -9.5t-98 -10.5q-39 0 -72 10q-2 16 -2 47q0 74 3 96q2 13 31.5  [...]
+<glyph unicode="&#xf1a9;" d="M1167 -50q-5 19 -24 5q-30 -22 -87 -39t-131 -17q-129 0 -193 49q-5 4 -13 4q-11 0 -26 -12q-7 -6 -7.5 -16t7.5 -20q34 -32 87.5 -46t102.5 -12.5t99 4.5q41 4 84.5 20.5t65 30t28.5 20.5q12 12 7 29zM1128 65q-19 47 -39 61q-23 15 -76 15q-47 0 -71 -10 q-29 -12 -78 -56q-26 -24 -12 -44q9 -8 17.5 -4.5t31.5 23.5q3 2 10.5 8.5t10.5 8.5t10 7t11.5 7t12.5 5t15 4.5t16.5 2.5t20.5 1q27 0 44.5 -7.5t23 -14.5t13.5 -22q10 -17 12.5 -20t12.5 1q23 12 14 34zM1483 346q0 22 -5 44.5t-16.5 45t-34 [...]
+<glyph unicode="&#xf1aa;" d="M1070 463l-160 -160l-151 -152l-30 -30q-65 -64 -151.5 -87t-171.5 -2q-16 -70 -72 -115t-129 -45q-85 0 -145 60.5t-60 145.5q0 72 44.5 128t113.5 72q-22 86 1 173t88 152l12 12l151 -152l-11 -11q-37 -37 -37 -89t37 -90q37 -37 89 -37t89 37l30 30l151 152l161 160z M729 1145l12 -12l-152 -152l-12 12q-37 37 -89 37t-89 -37t-37 -89.5t37 -89.5l29 -29l152 -152l160 -160l-151 -152l-161 160l-151 152l-30 30q-68 67 -90 159.5t5 179.5q-70 15 -115 71t-45 129q0 85 60 145.5t145 60.5q76 0 1 [...]
+<glyph unicode="&#xf1ab;" d="M654 458q-1 -3 -12.5 0.5t-31.5 11.5l-20 9q-44 20 -87 49q-7 5 -41 31.5t-38 28.5q-67 -103 -134 -181q-81 -95 -105 -110q-4 -2 -19.5 -4t-18.5 0q6 4 82 92q21 24 85.5 115t78.5 118q17 30 51 98.5t36 77.5q-8 1 -110 -33q-8 -2 -27.5 -7.5t-34.5 -9.5t-17 -5 q-2 -2 -2 -10.5t-1 -9.5q-5 -10 -31 -15q-23 -7 -47 0q-18 4 -28 21q-4 6 -5 23q6 2 24.5 5t29.5 6q58 16 105 32q100 35 102 35q10 2 43 19.5t44 21.5q9 3 21.5 8t14.5 5.5t6 -0.5q2 -12 -1 -33q0 -2 -12.5 -27t-26.5 -53.5t-17 -33.5q [...]
+<glyph unicode="&#xf1ac;" horiz-adv-x="1792" d="M288 1152q66 0 113 -47t47 -113v-1088q0 -66 -47 -113t-113 -47h-128q-66 0 -113 47t-47 113v1088q0 66 47 113t113 47h128zM1664 989q58 -34 93 -93t35 -128v-768q0 -106 -75 -181t-181 -75h-864q-66 0 -113 47t-47 113v1536q0 40 28 68t68 28h672q40 0 88 -20t76 -48 l152 -152q28 -28 48 -76t20 -88v-163zM928 0v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 -14 9 -23t23 -9h128q14 0 23 9t9 23zM928 256v128q0 14 -9 23t-23 9h-128q-14 0 -23 -9t-9 -23v-128q0 - [...]
+<glyph unicode="&#xf1ad;" d="M1344 1536q26 0 45 -19t19 -45v-1664q0 -26 -19 -45t-45 -19h-1280q-26 0 -45 19t-19 45v1664q0 26 19 45t45 19h1280zM512 1248v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 992v-64q0 -14 9 -23t23 -9h64q14 0 23 9 t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 736v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23zM512 480v-64q0 -14 9 -23t23 -9h64q14 0 23 9t9 23v64q0 14 -9 23t-23 9h-6 [...]
+<glyph unicode="&#xf1ae;" horiz-adv-x="1280" d="M1188 988l-292 -292v-824q0 -46 -33 -79t-79 -33t-79 33t-33 79v384h-64v-384q0 -46 -33 -79t-79 -33t-79 33t-33 79v824l-292 292q-28 28 -28 68t28 68t68 28t68 -28l228 -228h368l228 228q28 28 68 28t68 -28t28 -68t-28 -68zM864 1152q0 -93 -65.5 -158.5 t-158.5 -65.5t-158.5 65.5t-65.5 158.5t65.5 158.5t158.5 65.5t158.5 -65.5t65.5 -158.5z" />
+<glyph unicode="&#xf1b0;" horiz-adv-x="1664" d="M780 1064q0 -60 -19 -113.5t-63 -92.5t-105 -39q-76 0 -138 57.5t-92 135.5t-30 151q0 60 19 113.5t63 92.5t105 39q77 0 138.5 -57.5t91.5 -135t30 -151.5zM438 581q0 -80 -42 -139t-119 -59q-76 0 -141.5 55.5t-100.5 133.5t-35 152q0 80 42 139.5t119 59.5 q76 0 141.5 -55.5t100.5 -134t35 -152.5zM832 608q118 0 255 -97.5t229 -237t92 -254.5q0 -46 -17 -76.5t-48.5 -45t-64.5 -20t-76 -5.5q-68 0 -187.5 45t-182.5 45q-66 0 -192.5 -44.5t-200.5 -44.5q-183 0 -183 146q0 [...]
+<glyph unicode="&#xf1b1;" horiz-adv-x="768" d="M704 1008q0 -145 -57 -243.5t-152 -135.5l45 -821q2 -26 -16 -45t-44 -19h-192q-26 0 -44 19t-16 45l45 821q-95 37 -152 135.5t-57 243.5q0 128 42.5 249.5t117.5 200t160 78.5t160 -78.5t117.5 -200t42.5 -249.5z" />
+<glyph unicode="&#xf1b2;" horiz-adv-x="1792" d="M896 -93l640 349v636l-640 -233v-752zM832 772l698 254l-698 254l-698 -254zM1664 1024v-768q0 -35 -18 -65t-49 -47l-704 -384q-28 -16 -61 -16t-61 16l-704 384q-31 17 -49 47t-18 65v768q0 40 23 73t61 47l704 256q22 8 44 8t44 -8l704 -256q38 -14 61 -47t23 -73z " />
+<glyph unicode="&#xf1b3;" horiz-adv-x="2304" d="M640 -96l384 192v314l-384 -164v-342zM576 358l404 173l-404 173l-404 -173zM1664 -96l384 192v314l-384 -164v-342zM1600 358l404 173l-404 173l-404 -173zM1152 651l384 165v266l-384 -164v-267zM1088 1030l441 189l-441 189l-441 -189zM2176 512v-416q0 -36 -19 -67 t-52 -47l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-5 2 -7 4q-2 -2 -7 -4l-448 -224q-25 -14 -57 -14t-57 14l-448 224q-33 16 -52 47t-19 67v416q0 38 21.5 70t56.5 48l434 186v400q0 38 21.5 70t56.5 48l [...]
+<glyph unicode="&#xf1b4;" horiz-adv-x="2048" d="M1848 1197h-511v-124h511v124zM1596 771q-90 0 -146 -52.5t-62 -142.5h408q-18 195 -200 195zM1612 186q63 0 122 32t76 87h221q-100 -307 -427 -307q-214 0 -340.5 132t-126.5 347q0 208 130.5 345.5t336.5 137.5q138 0 240.5 -68t153 -179t50.5 -248q0 -17 -2 -47h-658 q0 -111 57.5 -171.5t166.5 -60.5zM277 236h296q205 0 205 167q0 180 -199 180h-302v-347zM277 773h281q78 0 123.5 36.5t45.5 113.5q0 144 -190 144h-260v-294zM0 1282h594q87 0 155 -14t126.5 -47.5t90 -96 [...]
+<glyph unicode="&#xf1b5;" d="M1248 1408q119 0 203.5 -84.5t84.5 -203.5v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960zM499 1041h-371v-787h382q117 0 197 57.5t80 170.5q0 158 -143 200q107 52 107 164q0 57 -19.5 96.5 t-56.5 60.5t-79 29.5t-97 8.5zM477 723h-176v184h163q119 0 119 -90q0 -94 -106 -94zM486 388h-185v217h189q124 0 124 -113q0 -104 -128 -104zM1136 356q-68 0 -104 38t-36 107h411q1 10 1 30q0 132 -74.5 220.5t-203.5 88.5q-128 0 - [...]
+<glyph unicode="&#xf1b6;" horiz-adv-x="1792" d="M1582 954q0 -101 -71.5 -172.5t-172.5 -71.5t-172.5 71.5t-71.5 172.5t71.5 172.5t172.5 71.5t172.5 -71.5t71.5 -172.5zM812 212q0 104 -73 177t-177 73q-27 0 -54 -6l104 -42q77 -31 109.5 -106.5t1.5 -151.5q-31 -77 -107 -109t-152 -1q-21 8 -62 24.5t-61 24.5 q32 -60 91 -96.5t130 -36.5q104 0 177 73t73 177zM1642 953q0 126 -89.5 215.5t-215.5 89.5q-127 0 -216.5 -89.5t-89.5 -215.5q0 -127 89.5 -216t216.5 -89q126 0 215.5 89t89.5 216zM1792 953q0 -189 -133.5 -32 [...]
+<glyph unicode="&#xf1b7;" d="M1242 889q0 80 -57 136.5t-137 56.5t-136.5 -57t-56.5 -136q0 -80 56.5 -136.5t136.5 -56.5t137 56.5t57 136.5zM632 301q0 -83 -58 -140.5t-140 -57.5q-56 0 -103 29t-72 77q52 -20 98 -40q60 -24 120 1.5t85 86.5q24 60 -1.5 120t-86.5 84l-82 33q22 5 42 5 q82 0 140 -57.5t58 -140.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v153l172 -69q20 -92 93.5 -152t168.5 -60q104 0 181 70t87 173l345 252q150 0 255.5 105.5t105.5 254.5q0 150 -105.5 2 [...]
+<glyph unicode="&#xf1b8;" horiz-adv-x="1792" d="M836 367l-15 -368l-2 -22l-420 29q-36 3 -67 31.5t-47 65.5q-11 27 -14.5 55t4 65t12 55t21.5 64t19 53q78 -12 509 -28zM449 953l180 -379l-147 92q-63 -72 -111.5 -144.5t-72.5 -125t-39.5 -94.5t-18.5 -63l-4 -21l-190 357q-17 26 -18 56t6 47l8 18q35 63 114 188 l-140 86zM1680 436l-188 -359q-12 -29 -36.5 -46.5t-43.5 -20.5l-18 -4q-71 -7 -219 -12l8 -164l-230 367l211 362l7 -173q170 -16 283 -5t170 33zM895 1360q-47 -63 -265 -435l-317 187l-19 12l225 356q20 31 6 [...]
+<glyph unicode="&#xf1b9;" horiz-adv-x="2048" d="M480 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM516 768h1016l-89 357q-2 8 -14 17.5t-21 9.5h-768q-9 0 -21 -9.5t-14 -17.5zM1888 448q0 66 -47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47t113 47t47 113zM2048 544v-384 q0 -14 -9 -23t-23 -9h-96v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-1024v-128q0 -80 -56 -136t-136 -56t-136 56t-56 136v128h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94  [...]
+<glyph unicode="&#xf1ba;" horiz-adv-x="2048" d="M1824 640q93 0 158.5 -65.5t65.5 -158.5v-384q0 -14 -9 -23t-23 -9h-96v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-1024v-64q0 -80 -56 -136t-136 -56t-136 56t-56 136v64h-96q-14 0 -23 9t-9 23v384q0 93 65.5 158.5t158.5 65.5h28l105 419q23 94 104 157.5 t179 63.5h128v224q0 14 9 23t23 9h448q14 0 23 -9t9 -23v-224h128q98 0 179 -63.5t104 -157.5l105 -419h28zM320 160q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM516 640h1016l-89 [...]
+<glyph unicode="&#xf1bb;" d="M1504 64q0 -26 -19 -45t-45 -19h-462q1 -17 6 -87.5t5 -108.5q0 -25 -18 -42.5t-43 -17.5h-320q-25 0 -43 17.5t-18 42.5q0 38 5 108.5t6 87.5h-462q-26 0 -45 19t-19 45t19 45l402 403h-229q-26 0 -45 19t-19 45t19 45l402 403h-197q-26 0 -45 19t-19 45t19 45l384 384 q19 19 45 19t45 -19l384 -384q19 -19 19 -45t-19 -45t-45 -19h-197l402 -403q19 -19 19 -45t-19 -45t-45 -19h-229l402 -403q19 -19 19 -45z" />
+<glyph unicode="&#xf1bc;" d="M1127 326q0 32 -30 51q-193 115 -447 115q-133 0 -287 -34q-42 -9 -42 -52q0 -20 13.5 -34.5t35.5 -14.5q5 0 37 8q132 27 243 27q226 0 397 -103q19 -11 33 -11q19 0 33 13.5t14 34.5zM1223 541q0 40 -35 61q-237 141 -548 141q-153 0 -303 -42q-48 -13 -48 -64 q0 -25 17.5 -42.5t42.5 -17.5q7 0 37 8q122 33 251 33q279 0 488 -124q24 -13 38 -13q25 0 42.5 17.5t17.5 42.5zM1331 789q0 47 -40 70q-126 73 -293 110.5t-343 37.5q-204 0 -364 -47q-23 -7 -38.5 -25.5t-15.5 -48.5q0 -31 20.5 -52t [...]
+<glyph unicode="&#xf1bd;" horiz-adv-x="1024" d="M1024 1233l-303 -582l24 -31h279v-415h-507l-44 -30l-142 -273l-30 -30h-301v303l303 583l-24 30h-279v415h507l44 30l142 273l30 30h301v-303z" />
+<glyph unicode="&#xf1be;" horiz-adv-x="2304" d="M784 164l16 241l-16 523q-1 10 -7.5 17t-16.5 7q-9 0 -16 -7t-7 -17l-14 -523l14 -241q1 -10 7.5 -16.5t15.5 -6.5q22 0 24 23zM1080 193l11 211l-12 586q0 16 -13 24q-8 5 -16 5t-16 -5q-13 -8 -13 -24l-1 -6l-10 -579q0 -1 11 -236v-1q0 -10 6 -17q9 -11 23 -11 q11 0 20 9q9 7 9 20zM35 533l20 -128l-20 -126q-2 -9 -9 -9t-9 9l-17 126l17 128q2 9 9 9t9 -9zM121 612l26 -207l-26 -203q-2 -9 -10 -9q-9 0 -9 10l-23 202l23 207q0 9 9 9q8 0 10 -9zM401 159zM213 650l25 -245l [...]
+<glyph unicode="&#xf1c0;" d="M768 768q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 0q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127 t443 -43zM768 384q237 0 443 43t325 127v-170q0 -69 -103 -128t-280 -93.5t-385 -34.5t-385 34.5t-280 93.5t-103 128v170q119 -84 325 -127t443 -43zM768 1536q208 0 385 -34.5t280 -93.5t103 -128v-128q0 -69 -103 -128t-280  [...]
+<glyph unicode="&#xf1c1;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M894 465q33 -26 84 -56q59 7 117 7q147 0 177 -49q16 -22 2 -52q0 -1 -1 -2l-2 -2v-1q-6 -38 -71 -38q-48 0 -115 20t-130 53q-221 -24 -392 -83q-153 -262 -242 -262q-15 0 -28 7l-24 12q-1 1 -6 5q-10 10 -6 36q9 40 56 91.5t13 [...]
+<glyph unicode="&#xf1c2;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M233 768v-107h70l164 -661h159l128 485q7 20 10 46q2 16 2 24h4l3 -24q1 -3 3.5 -20t5.5 -26l128 -485h159l164 661h70v107h-300v-107h90l-99 -438q-5 -20 -7 -46l-2 -21h-4l-3 21q-1 5 -4 21t-5 25l-144 545h-114l-144 -545q-2 - [...]
+<glyph unicode="&#xf1c3;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M429 106v-106h281v106h-75l103 161q5 7 10 16.5t7.5 13.5t3.5 4h2q1 -4 5 -10q2 -4 4.5 -7.5t6 -8t6.5 -8.5l107 -161h-76v-106h291v106h-68l-192 273l195 282h67v107h-279v-107h74l-103 -159q-4 -7 -10 -16.5t-9 -13.5l-2 -3h-2q [...]
+<glyph unicode="&#xf1c4;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M416 106v-106h327v106h-93v167h137q76 0 118 15q67 23 106.5 87t39.5 146q0 81 -37 141t-100 87q-48 19 -130 19h-368v-107h92v-555h-92zM769 386h-119v268h120q52 0 83 -18q56 -33 56 -115q0 -89 -62 -120q-31 -15 -78 -15z" />
+<glyph unicode="&#xf1c5;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M1280 320v-320h-1024v192l192 192l128 -128l384 384zM448 512q-80 0 -136 56t-56 136t56 136t136 56t136 -56t56 -136t-56 -136t-136 -56z" />
+<glyph unicode="&#xf1c6;" d="M640 1152v128h-128v-128h128zM768 1024v128h-128v-128h128zM640 896v128h-128v-128h128zM768 768v128h-128v-128h128zM1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400 v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-128v-128h-128v128h-512v-1536h1280zM781 593l107 -349q8 -27 8 -52q0 -83 -72.5 -137.5t-183.5 -54.5t-183.5 54.5t-72.5 137. [...]
+<glyph unicode="&#xf1c7;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M620 686q20 -8 20 -30v-544q0 -22 -20 -30q-8 -2 -12 -2q-12 0 -23 9l-166 167h-131q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h131l166 167q16 15 35 7zM1037 -3q31 0 50 24q129 159 129 363t-129 363q-16 21 -43 24t-47 -14q-21 -1 [...]
+<glyph unicode="&#xf1c8;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M768 768q52 0 90 -38t38 -90v-384q0 -52 -38 -90t-90 -38h-384q-52 0 -90 38t-38 90v384q0 52 38 90t90 38h384zM1260 766q20 -8 20 -30v-576q0 -22 -20 -30q-8 -2 -12 -2q-14 0 -23 9l-265 266v90l265 266q9 9 23 9q4 0 12 -2z" />
+<glyph unicode="&#xf1c9;" d="M1468 1156q28 -28 48 -76t20 -88v-1152q0 -40 -28 -68t-68 -28h-1344q-40 0 -68 28t-28 68v1600q0 40 28 68t68 28h896q40 0 88 -20t76 -48zM1024 1400v-376h376q-10 29 -22 41l-313 313q-12 12 -41 22zM1408 -128v1024h-416q-40 0 -68 28t-28 68v416h-768v-1536h1280z M480 768q8 11 21 12.5t24 -6.5l51 -38q11 -8 12.5 -21t-6.5 -24l-182 -243l182 -243q8 -11 6.5 -24t-12.5 -21l-51 -38q-11 -8 -24 -6.5t-21 12.5l-226 301q-14 19 0 38zM1282 467q14 -19 0 -38l-226 -301q-8 -11 -21 -12.5t-24 6 [...]
+<glyph unicode="&#xf1ca;" d="M1497 709v-198q-101 -23 -198 -23q-65 -136 -165.5 -271t-181.5 -215.5t-128 -106.5q-80 -45 -162 3q-28 17 -60.5 43.5t-85 83.5t-102.5 128.5t-107.5 184t-105.5 244t-91.5 314.5t-70.5 390h283q26 -218 70 -398.5t104.5 -317t121.5 -235.5t140 -195q169 169 287 406 q-142 72 -223 220t-81 333q0 192 104 314.5t284 122.5q178 0 273 -105.5t95 -297.5q0 -159 -58 -286q-7 -1 -19.5 -3t-46 -2t-63 6t-62 25.5t-50.5 51.5q31 103 31 184q0 87 -29 132t-79 45q-53 0 -85 -49.5t-32 -140.5q0 -186 10 [...]
+<glyph unicode="&#xf1cb;" horiz-adv-x="1792" d="M216 367l603 -402v359l-334 223zM154 511l193 129l-193 129v-258zM973 -35l603 402l-269 180l-334 -223v-359zM896 458l272 182l-272 182l-272 -182zM485 733l334 223v359l-603 -402zM1445 640l193 -129v258zM1307 733l269 180l-603 402v-359zM1792 913v-546 q0 -41 -34 -64l-819 -546q-21 -13 -43 -13t-43 13l-819 546q-34 23 -34 64v546q0 41 34 64l819 546q21 13 43 13t43 -13l819 -546q34 -23 34 -64z" />
+<glyph unicode="&#xf1cc;" horiz-adv-x="2048" d="M1800 764q111 -46 179.5 -145.5t68.5 -221.5q0 -164 -118 -280.5t-285 -116.5q-4 0 -11.5 0.5t-10.5 0.5h-1209h-1h-2h-5q-170 10 -288 125.5t-118 280.5q0 110 55 203t147 147q-12 39 -12 82q0 115 82 196t199 81q95 0 172 -58q75 154 222.5 248t326.5 94 q166 0 306 -80.5t221.5 -218.5t81.5 -301q0 -6 -0.5 -18t-0.5 -18zM468 498q0 -122 84 -193t208 -71q137 0 240 99q-16 20 -47.5 56.5t-43.5 50.5q-67 -65 -144 -65q-55 0 -93.5 33.5t-38.5 87.5q0 53 38.5 87t91.5 34q44  [...]
+<glyph unicode="&#xf1cd;" horiz-adv-x="1792" d="M896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM896 1408q-190 0 -361 -90l194 -194q82 28 167 28t167 -28l194 194q-171 90 -361 90zM218 279l194 194 q-28 82 -28 167t28 167l-194 194q-90 -171 -90 -361t90 -361zM896 -128q190 0 361 90l-194 194q-82 -28 -167 -28t-167 28l-194 -194q171 -90 361 -90zM896 256q159 0 271.5 112.5t112.5 271.5t-112.5 271.5t-2 [...]
+<glyph unicode="&#xf1ce;" horiz-adv-x="1792" d="M1792 640q0 -182 -71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348q0 222 101 414.5t276.5 317t390.5 155.5v-260q-221 -45 -366.5 -221t-145.5 -406q0 -130 51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5 q0 230 -145.5 406t-366.5 221v260q215 -31 390.5 -155.5t276.5 -317t101 -414.5z" />
+<glyph unicode="&#xf1d0;" horiz-adv-x="1792" d="M19 662q8 217 116 406t305 318h5q0 -1 -1 -3q-8 -8 -28 -33.5t-52 -76.5t-60 -110.5t-44.5 -135.5t-14 -150.5t39 -157.5t108.5 -154q50 -50 102 -69.5t90.5 -11.5t69.5 23.5t47 32.5l16 16q39 51 53 116.5t6.5 122.5t-21 107t-26.5 80l-14 29q-10 25 -30.5 49.5t-43 41 t-43.5 29.5t-35 19l-13 6l104 115q39 -17 78 -52t59 -61l19 -27q1 48 -18.5 103.5t-40.5 87.5l-20 31l161 183l160 -181q-33 -46 -52.5 -102.5t-22.5 -90.5l-4 -33q22 37 61.5 72.5t67.5 52.5l28 17l103 -115 [...]
+<glyph unicode="&#xf1d1;" horiz-adv-x="1792" d="M874 -102v-66q-208 6 -385 109.5t-283 275.5l58 34q29 -49 73 -99l65 57q148 -168 368 -212l-17 -86q65 -12 121 -13zM276 428l-83 -28q22 -60 49 -112l-57 -33q-98 180 -98 385t98 385l57 -33q-30 -56 -49 -112l82 -28q-35 -100 -35 -212q0 -109 36 -212zM1528 251 l58 -34q-106 -172 -283 -275.5t-385 -109.5v66q56 1 121 13l-17 86q220 44 368 212l65 -57q44 50 73 99zM1377 805l-233 -80q14 -42 14 -85t-14 -85l232 -80q-31 -92 -98 -169l-185 162q-57 -67 -147 -85l48 -241 [...]
+<glyph unicode="&#xf1d2;" d="M582 228q0 -66 -93 -66q-107 0 -107 63q0 64 98 64q102 0 102 -61zM546 694q0 -85 -74 -85q-77 0 -77 84q0 90 77 90q36 0 55 -25.5t19 -63.5zM712 769v125q-78 -29 -135 -29q-50 29 -110 29q-86 0 -145 -57t-59 -143q0 -50 29.5 -102t73.5 -67v-3q-38 -17 -38 -85 q0 -53 41 -77v-3q-113 -37 -113 -139q0 -45 20 -78.5t54 -51t72 -25.5t81 -8q224 0 224 188q0 67 -48 99t-126 46q-27 5 -51.5 20.5t-24.5 39.5q0 44 49 52q77 15 122 70t45 134q0 24 -10 52q37 9 49 13zM771 350h137q-2 27 -2 82v387 [...]
+<glyph unicode="&#xf1d3;" horiz-adv-x="1792" d="M595 22q0 100 -165 100q-158 0 -158 -104q0 -101 172 -101q151 0 151 105zM536 777q0 61 -30 102t-89 41q-124 0 -124 -145q0 -135 124 -135q119 0 119 137zM805 1101v-202q-36 -12 -79 -22q16 -43 16 -84q0 -127 -73 -216.5t-197 -112.5q-40 -8 -59.5 -27t-19.5 -58 q0 -31 22.5 -51.5t58 -32t78.5 -22t86 -25.5t78.5 -37.5t58 -64t22.5 -98.5q0 -304 -363 -304q-69 0 -130 12.5t-116 41t-87.5 82t-32.5 127.5q0 165 182 225v4q-67 41 -67 126q0 109 63 137v4q-72 24 -119.5 10 [...]
+<glyph unicode="&#xf1d4;" d="M825 547l343 588h-150q-21 -39 -63.5 -118.5t-68 -128.5t-59.5 -118.5t-60 -128.5h-3q-21 48 -44.5 97t-52 105.5t-46.5 92t-54 104.5t-49 95h-150l323 -589v-435h134v436zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960 q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z" />
+<glyph unicode="&#xf1d5;" horiz-adv-x="1280" d="M842 964q0 -80 -57 -136.5t-136 -56.5q-60 0 -111 35q-62 -67 -115 -146q-247 -371 -202 -859q1 -22 -12.5 -38.5t-34.5 -18.5h-5q-20 0 -35 13.5t-17 33.5q-14 126 -3.5 247.5t29.5 217t54 186t69 155.5t74 125q61 90 132 165q-16 35 -16 77q0 80 56.5 136.5t136.5 56.5 t136.5 -56.5t56.5 -136.5zM1223 953q0 -158 -78 -292t-212.5 -212t-292.5 -78q-64 0 -131 14q-21 5 -32.5 23.5t-6.5 39.5q5 20 23 31.5t39 7.5q51 -13 108 -13q97 0 186 38t153 102t102 153t38 186t-38 186 [...]
+<glyph unicode="&#xf1d6;" horiz-adv-x="1792" d="M270 730q-8 19 -8 52q0 20 11 49t24 45q-1 22 7.5 53t22.5 43q0 139 92.5 288.5t217.5 209.5q139 66 324 66q133 0 266 -55q49 -21 90 -48t71 -56t55 -68t42 -74t32.5 -84.5t25.5 -89.5t22 -98l1 -5q55 -83 55 -150q0 -14 -9 -40t-9 -38q0 -1 1.5 -3.5t3.5 -5t2 -3.5 q77 -114 120.5 -214.5t43.5 -208.5q0 -43 -19.5 -100t-55.5 -57q-9 0 -19.5 7.5t-19 17.5t-19 26t-16 26.5t-13.5 26t-9 17.5q-1 1 -3 1l-5 -4q-59 -154 -132 -223q20 -20 61.5 -38.5t69 -41.5t35.5 -65q-2 -4 - [...]
+<glyph unicode="&#xf1d7;" horiz-adv-x="2048" d="M580 1075q0 41 -25 66t-66 25q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 66 24.5t25 65.5zM1323 568q0 28 -25.5 50t-65.5 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q40 0 65.5 22t25.5 51zM1087 1075q0 41 -24.5 66t-65.5 25 q-43 0 -76 -25.5t-33 -65.5q0 -39 33 -64.5t76 -25.5q41 0 65.5 24.5t24.5 65.5zM1722 568q0 28 -26 50t-65 22q-27 0 -49.5 -22.5t-22.5 -49.5q0 -28 22.5 -50.5t49.5 -22.5q39 0 65 22t26 51zM1456 965q-31 4 -7 [...]
+<glyph unicode="&#xf1d8;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-453 185l-242 -295q-18 -23 -49 -23q-13 0 -22 4q-19 7 -30.5 23.5t-11.5 36.5v349l864 1059l-1069 -925l-395 162q-37 14 -40 55q-2 40 32 59l1664 960q15 9 32 9q20 0 36 -11z" />
+<glyph unicode="&#xf1d9;" horiz-adv-x="1792" d="M1764 1525q33 -24 27 -64l-256 -1536q-5 -29 -32 -45q-14 -8 -31 -8q-11 0 -24 5l-527 215l-298 -327q-18 -21 -47 -21q-14 0 -23 4q-19 7 -30 23.5t-11 36.5v452l-472 193q-37 14 -40 55q-3 39 32 59l1664 960q35 21 68 -2zM1422 26l221 1323l-1434 -827l336 -137 l863 639l-478 -797z" />
+<glyph unicode="&#xf1da;" d="M1536 640q0 -156 -61 -298t-164 -245t-245 -164t-298 -61q-172 0 -327 72.5t-264 204.5q-7 10 -6.5 22.5t8.5 20.5l137 138q10 9 25 9q16 -2 23 -12q73 -95 179 -147t225 -52q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5 t-163.5 109.5t-198.5 40.5q-98 0 -188 -35.5t-160 -101.5l137 -138q31 -30 14 -69q-17 -40 -59 -40h-448q-26 0 -45 19t-19 45v448q0 42 40 59q39 17 69 -14l130 -129q107 101 244.5 156.5t284.5 55.5q156 0 298 -61t245 -164t164 -245t61 - [...]
+<glyph unicode="&#xf1db;" d="M768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 -51t248.5 51t204 136.5t136.5 204t51 248.5t-51 248.5t-136.5 204t-204 136.5t-248.5 51zM1536 640q0 -209 -103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103 t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf1dc;" horiz-adv-x="1792" d="M1682 -128q-44 0 -132.5 3.5t-133.5 3.5q-44 0 -132 -3.5t-132 -3.5q-24 0 -37 20.5t-13 45.5q0 31 17 46t39 17t51 7t45 15q33 21 33 140l-1 391q0 21 -1 31q-13 4 -50 4h-675q-38 0 -51 -4q-1 -10 -1 -31l-1 -371q0 -142 37 -164q16 -10 48 -13t57 -3.5t45 -15 t20 -45.5q0 -26 -12.5 -48t-36.5 -22q-47 0 -139.5 3.5t-138.5 3.5q-43 0 -128 -3.5t-127 -3.5q-23 0 -35.5 21t-12.5 45q0 30 15.5 45t36 17.5t47.5 7.5t42 15q33 23 33 143l-1 57v813q0 3 0.5 26t0 36.5t-1.5 38.5 [...]
+<glyph unicode="&#xf1dd;" horiz-adv-x="1280" d="M1278 1347v-73q0 -29 -18.5 -61t-42.5 -32q-50 0 -54 -1q-26 -6 -32 -31q-3 -11 -3 -64v-1152q0 -25 -18 -43t-43 -18h-108q-25 0 -43 18t-18 43v1218h-143v-1218q0 -25 -17.5 -43t-43.5 -18h-108q-26 0 -43.5 18t-17.5 43v496q-147 12 -245 59q-126 58 -192 179 q-64 117 -64 259q0 166 88 286q88 118 209 159q111 37 417 37h479q25 0 43 -18t18 -43z" />
+<glyph unicode="&#xf1de;" d="M352 128v-128h-352v128h352zM704 256q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM864 640v-128h-864v128h864zM224 1152v-128h-224v128h224zM1536 128v-128h-736v128h736zM576 1280q26 0 45 -19t19 -45v-256 q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1216 768q26 0 45 -19t19 -45v-256q0 -26 -19 -45t-45 -19h-256q-26 0 -45 19t-19 45v256q0 26 19 45t45 19h256zM1536 640v-128h-224v128h224zM1536 1 [...]
+<glyph unicode="&#xf1e0;" d="M1216 512q133 0 226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5q0 12 2 34l-360 180q-92 -86 -218 -86q-133 0 -226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5q126 0 218 -86l360 180q-2 22 -2 34q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5q-126 0 -218 86l-360 -180q2 -22 2 -34t-2 -34l360 -180q92 86 218 86z" />
+<glyph unicode="&#xf1e1;" d="M1280 341q0 88 -62.5 151t-150.5 63q-84 0 -145 -58l-241 120q2 16 2 23t-2 23l241 120q61 -58 145 -58q88 0 150.5 63t62.5 151t-62.5 150.5t-150.5 62.5t-151 -62.5t-63 -150.5q0 -7 2 -23l-241 -120q-62 57 -145 57q-88 0 -150.5 -62.5t-62.5 -150.5t62.5 -150.5 t150.5 -62.5q83 0 145 57l241 -120q-2 -16 -2 -23q0 -88 63 -150.5t151 -62.5t150.5 62.5t62.5 150.5zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960 [...]
+<glyph unicode="&#xf1e2;" horiz-adv-x="1792" d="M571 947q-10 25 -34 35t-49 0q-108 -44 -191 -127t-127 -191q-10 -25 0 -49t35 -34q13 -5 24 -5q42 0 60 40q34 84 98.5 148.5t148.5 98.5q25 11 35 35t0 49zM1513 1303l46 -46l-244 -243l68 -68q19 -19 19 -45.5t-19 -45.5l-64 -64q89 -161 89 -343q0 -143 -55.5 -273.5 t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5q182 0 343 -89l64 64q19 19 45.5 19t45.5 -19l68 -68zM1521 1359q-10 -10 -22 -10q- [...]
+<glyph unicode="&#xf1e3;" horiz-adv-x="1792" d="M609 720l287 208l287 -208l-109 -336h-355zM896 1536q182 0 348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348t71 348t191 286t286 191t348 71zM1515 186q149 203 149 454v3l-102 -89l-240 224l63 323 l134 -12q-150 206 -389 282l53 -124l-287 -159l-287 159l53 124q-239 -76 -389 -282l135 12l62 -323l-240 -224l-102 89v-3q0 -251 149 -454l30 132l326 -40l139 -298l-116 -69q117 -39 240 -39t240 39l-116 69l13 [...]
+<glyph unicode="&#xf1e4;" horiz-adv-x="1792" d="M448 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM256 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM832 224v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23 v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM640 608v-192q0 -14 -9 -23t-23 -9h-192q-14 0 -23 9t-9 23v192q0 14 9 23t23 9h192q14 0 23 -9t9 -23zM66 768q-28 0 -47 19t-19 46v129h514v-129q0 -27 -19 -46t [...]
+<glyph unicode="&#xf1e5;" horiz-adv-x="1792" d="M704 1216v-768q0 -26 -19 -45t-45 -19v-576q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v512l249 873q7 23 31 23h424zM1024 1216v-704h-256v704h256zM1792 320v-512q0 -26 -19 -45t-45 -19h-512q-26 0 -45 19t-19 45v576q-26 0 -45 19t-19 45v768h424q24 0 31 -23z M736 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23zM1408 1504v-224h-352v224q0 14 9 23t23 9h288q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf1e6;" horiz-adv-x="1792" d="M1755 1083q37 -37 37 -90t-37 -91l-401 -400l150 -150l-160 -160q-163 -163 -389.5 -186.5t-411.5 100.5l-362 -362h-181v181l362 362q-124 185 -100.5 411.5t186.5 389.5l160 160l150 -150l400 401q38 37 91 37t90 -37t37 -90.5t-37 -90.5l-400 -401l234 -234l401 400 q38 37 91 37t90 -37z" />
+<glyph unicode="&#xf1e7;" horiz-adv-x="1792" d="M873 796q0 -83 -63.5 -142.5t-152.5 -59.5t-152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59t152.5 -59t63.5 -143zM1375 796q0 -83 -63 -142.5t-153 -59.5q-89 0 -152.5 59.5t-63.5 142.5q0 84 63.5 143t152.5 59q90 0 153 -59t63 -143zM1600 616v667q0 87 -32 123.5 t-111 36.5h-1112q-83 0 -112.5 -34t-29.5 -126v-673q43 -23 88.5 -40t81 -28t81 -18.5t71 -11t70 -4t58.5 -0.5t56.5 2t44.5 2q68 1 95 -27q6 -6 10 -9q26 -25 61 -51q7 91 118 87q5 0 36.5 -1.5t43 -2t45.5 -1 [...]
+<glyph unicode="&#xf1e8;" horiz-adv-x="1792" d="M896 1102v-434h-145v434h145zM1294 1102v-434h-145v434h145zM1294 342l253 254v795h-1194v-1049h326v-217l217 217h398zM1692 1536v-1013l-434 -434h-326l-217 -217h-217v217h-398v1158l109 289h1483z" />
+<glyph unicode="&#xf1e9;" d="M773 217v-127q-1 -292 -6 -305q-12 -32 -51 -40q-54 -9 -181.5 38t-162.5 89q-13 15 -17 36q-1 12 4 26q4 10 34 47t181 216q1 0 60 70q15 19 39.5 24.5t49.5 -3.5q24 -10 37.5 -29t12.5 -42zM624 468q-3 -55 -52 -70l-120 -39q-275 -88 -292 -88q-35 2 -54 36 q-12 25 -17 75q-8 76 1 166.5t30 124.5t56 32q13 0 202 -77q70 -29 115 -47l84 -34q23 -9 35.5 -30.5t11.5 -48.5zM1450 171q-7 -54 -91.5 -161t-135.5 -127q-37 -14 -63 7q-14 10 -184 287l-47 77q-14 21 -11.5 46t19.5 46q35 43 83 26q1 [...]
+<glyph unicode="&#xf1ea;" horiz-adv-x="2048" d="M1024 1024h-384v-384h384v384zM1152 384v-128h-640v128h640zM1152 1152v-640h-640v640h640zM1792 384v-128h-512v128h512zM1792 640v-128h-512v128h512zM1792 896v-128h-512v128h512zM1792 1152v-128h-512v128h512zM256 192v960h-128v-960q0 -26 19 -45t45 -19t45 19 t19 45zM1920 192v1088h-1536v-1088q0 -33 -11 -64h1483q26 0 45 19t19 45zM2048 1408v-1216q0 -80 -56 -136t-136 -56h-1664q-80 0 -136 56t-56 136v1088h256v128h1792z" />
+<glyph unicode="&#xf1eb;" horiz-adv-x="2048" d="M1024 13q-20 0 -93 73.5t-73 93.5q0 32 62.5 54t103.5 22t103.5 -22t62.5 -54q0 -20 -73 -93.5t-93 -73.5zM1294 284q-2 0 -40 25t-101.5 50t-128.5 25t-128.5 -25t-101 -50t-40.5 -25q-18 0 -93.5 75t-75.5 93q0 13 10 23q78 77 196 121t233 44t233 -44t196 -121 q10 -10 10 -23q0 -18 -75.5 -93t-93.5 -75zM1567 556q-11 0 -23 8q-136 105 -252 154.5t-268 49.5q-85 0 -170.5 -22t-149 -53t-113.5 -62t-79 -53t-31 -22q-17 0 -92 75t-75 93q0 12 10 22q132 132 320 205t380 73 [...]
+<glyph unicode="&#xf1ec;" horiz-adv-x="1792" d="M384 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM384 384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1152 0q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM768 384q0 53 -37.5 90.5t-90.5 37.5t-90. [...]
+<glyph unicode="&#xf1ed;" horiz-adv-x="1792" d="M1112 1090q0 159 -237 159h-70q-32 0 -59.5 -21.5t-34.5 -52.5l-63 -276q-2 -5 -2 -16q0 -24 17 -39.5t41 -15.5h53q69 0 128.5 13t112.5 41t83.5 81.5t30.5 126.5zM1716 938q0 -265 -220 -428q-219 -161 -612 -161h-61q-32 0 -59 -21.5t-34 -52.5l-73 -316 q-8 -36 -40.5 -61.5t-69.5 -25.5h-213q-31 0 -53 20t-22 51q0 10 13 65h151q34 0 64 23.5t38 56.5l73 316q8 33 37.5 57t63.5 24h61q390 0 607 160t217 421q0 129 -51 207q183 -92 183 -335zM1533 1123q0 -264 -221 -428q [...]
+<glyph unicode="&#xf1ee;" horiz-adv-x="1792" d="M602 949q19 -61 31 -123.5t17 -141.5t-14 -159t-62 -145q-21 81 -67 157t-95.5 127t-99 90.5t-78.5 57.5t-33 19q-62 34 -81.5 100t14.5 128t101 81.5t129 -14.5q138 -83 238 -177zM927 1236q11 -25 20.5 -46t36.5 -100.5t42.5 -150.5t25.5 -179.5t0 -205.5t-47.5 -209.5 t-105.5 -208.5q-51 -72 -138 -72q-54 0 -98 31q-57 40 -69 109t28 127q60 85 81 195t13 199.5t-32 180.5t-39 128t-22 52q-31 63 -8.5 129.5t85.5 97.5q34 17 75 17q47 0 88.5 -25t63.5 -69zM1248 567q-17 - [...]
+<glyph unicode="&#xf1f0;" horiz-adv-x="2304" d="M1975 546h-138q14 37 66 179l3 9q4 10 10 26t9 26l12 -55zM531 611l-58 295q-11 54 -75 54h-268l-2 -13q311 -79 403 -336zM710 960l-162 -438l-17 89q-26 70 -85 129.5t-131 88.5l135 -510h175l261 641h-176zM849 318h166l104 642h-166zM1617 944q-69 27 -149 27 q-123 0 -201 -59t-79 -153q-1 -102 145 -174q48 -23 67 -41t19 -39q0 -30 -30 -46t-69 -16q-86 0 -156 33l-22 11l-23 -144q74 -34 185 -34q130 -1 208.5 59t80.5 160q0 106 -140 174q-49 25 -71 42t-22 38q0 22 24 [...]
+<glyph unicode="&#xf1f1;" horiz-adv-x="2304" d="M671 603h-13q-47 0 -47 -32q0 -22 20 -22q17 0 28 15t12 39zM1066 639h62v3q1 4 0.5 6.5t-1 7t-2 8t-4.5 6.5t-7.5 5t-11.5 2q-28 0 -36 -38zM1606 603h-12q-48 0 -48 -32q0 -22 20 -22q17 0 28 15t12 39zM1925 629q0 41 -30 41q-19 0 -31 -20t-12 -51q0 -42 28 -42 q20 0 32.5 20t12.5 52zM480 770h87l-44 -262h-56l32 201l-71 -201h-39l-4 200l-34 -200h-53l44 262h81l2 -163zM733 663q0 -6 -4 -42q-16 -101 -17 -113h-47l1 22q-20 -26 -58 -26q-23 0 -37.5 16t-14.5 42q0 39  [...]
+<glyph unicode="&#xf1f2;" horiz-adv-x="2304" d="M313 759q0 -51 -36 -84q-29 -26 -89 -26h-17v220h17q61 0 89 -27q36 -31 36 -83zM2089 824q0 -52 -64 -52h-19v101h20q63 0 63 -49zM380 759q0 74 -50 120.5t-129 46.5h-95v-333h95q74 0 119 38q60 51 60 128zM410 593h65v333h-65v-333zM730 694q0 40 -20.5 62t-75.5 42 q-29 10 -39.5 19t-10.5 23q0 16 13.5 26.5t34.5 10.5q29 0 53 -27l34 44q-41 37 -98 37q-44 0 -74 -27.5t-30 -67.5q0 -35 18 -55.5t64 -36.5q37 -13 45 -19q19 -12 19 -34q0 -20 -14 -33.5t-36 -13.5q-48 0  [...]
+<glyph unicode="&#xf1f3;" horiz-adv-x="2304" d="M119 854h89l-45 108zM740 328l74 79l-70 79h-163v-49h142v-55h-142v-54h159zM898 406l99 -110v217zM1186 453q0 33 -40 33h-84v-69h83q41 0 41 36zM1475 457q0 29 -42 29h-82v-61h81q43 0 43 32zM1197 923q0 29 -42 29h-82v-60h81q43 0 43 31zM1656 854h89l-44 108z M699 1009v-271h-66v212l-94 -212h-57l-94 212v-212h-132l-25 60h-135l-25 -60h-70l116 271h96l110 -257v257h106l85 -184l77 184h108zM1255 453q0 -20 -5.5 -35t-14 -25t-22.5 -16.5t-26 -10t-31.5 -4.5t-31.5 -1 [...]
+<glyph unicode="&#xf1f4;" horiz-adv-x="2304" d="M322 689h-15q-19 0 -19 18q0 28 19 85q5 15 15 19.5t28 4.5q77 0 77 -49q0 -41 -30.5 -59.5t-74.5 -18.5zM664 528q-47 0 -47 29q0 62 123 62l3 -3q-5 -88 -79 -88zM1438 687h-15q-19 0 -19 19q0 28 19 85q5 15 14.5 19t28.5 4q77 0 77 -49q0 -41 -30.5 -59.5 t-74.5 -18.5zM1780 527q-47 0 -47 30q0 62 123 62l3 -3q-5 -89 -79 -89zM373 894h-128q-8 0 -14.5 -4t-8.5 -7.5t-7 -12.5q-3 -7 -45 -190t-42 -192q0 -7 5.5 -12.5t13.5 -5.5h62q25 0 32.5 34.5l15 69t32.5 34.5q47 0  [...]
+<glyph unicode="&#xf1f5;" horiz-adv-x="2304" d="M1597 633q0 -69 -21 -106q-19 -35 -52 -35q-23 0 -41 9v224q29 30 57 30q57 0 57 -122zM2035 669h-110q6 98 56 98q51 0 54 -98zM476 534q0 59 -33 91.5t-101 57.5q-36 13 -52 24t-16 25q0 26 38 26q58 0 124 -33l18 112q-67 32 -149 32q-77 0 -123 -38q-48 -39 -48 -109 q0 -58 32.5 -90.5t99.5 -56.5q39 -14 54.5 -25.5t15.5 -27.5q0 -31 -48 -31q-29 0 -70 12.5t-72 30.5l-18 -113q72 -41 168 -41q81 0 129 37q51 41 51 117zM771 749l19 111h-96v135l-129 -21l-18 -114l-46 - [...]
+<glyph unicode="&#xf1f6;" horiz-adv-x="2048" d="M1558 684q61 -356 298 -556q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5zM1024 -176q16 0 16 16t-16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5zM2026 1424q8 -10 7.5 -23.5t-10.5 -22.5 l-1872 -1622q-10 -8 -23.5 -7t-21.5 11l-84 96q-8 10 -7.5 23.5t10.5 21.5l186 161q-19 32 -19 66q50 42 91 88t85 119.5t74.5 158.5t50 206t19.5 260q0 152 117 282.5t307 158.5q-8 19 -8 39q0 40 28 68t68  [...]
+<glyph unicode="&#xf1f7;" horiz-adv-x="2048" d="M1040 -160q0 16 -16 16q-59 0 -101.5 42.5t-42.5 101.5q0 16 -16 16t-16 -16q0 -73 51.5 -124.5t124.5 -51.5q16 0 16 16zM503 315l877 760q-42 88 -132.5 146.5t-223.5 58.5q-93 0 -169.5 -31.5t-121.5 -80.5t-69 -103t-24 -105q0 -384 -137 -645zM1856 128 q0 -52 -38 -90t-90 -38h-448q0 -106 -75 -181t-181 -75t-180.5 74.5t-75.5 180.5l149 129h757q-166 187 -227 459l111 97q61 -356 298 -556zM1942 1520l84 -96q8 -10 7.5 -23.5t-10.5 -22.5l-1872 -1622q-10 -8 -23.5 -7 [...]
+<glyph unicode="&#xf1f8;" horiz-adv-x="1408" d="M512 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM768 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM1024 160v704q0 14 -9 23t-23 9h-64q-14 0 -23 -9t-9 -23v-704 q0 -14 9 -23t23 -9h64q14 0 23 9t9 23zM480 1152h448l-48 117q-7 9 -17 11h-317q-10 -2 -17 -11zM1408 1120v-64q0 -14 -9 -23t-23 -9h-96v-948q0 -83 -47 -143.5t-113 -60.5h-832q-66 0 -113 58.5t-47 141.5v [...]
+<glyph unicode="&#xf1f9;" d="M1150 462v-109q0 -50 -36.5 -89t-94 -60.5t-118 -32.5t-117.5 -11q-205 0 -342.5 139t-137.5 346q0 203 136 339t339 136q34 0 75.5 -4.5t93 -18t92.5 -34t69 -56.5t28 -81v-109q0 -16 -16 -16h-118q-16 0 -16 16v70q0 43 -65.5 67.5t-137.5 24.5q-140 0 -228.5 -91.5 t-88.5 -237.5q0 -151 91.5 -249.5t233.5 -98.5q68 0 138 24t70 66v70q0 7 4.5 11.5t10.5 4.5h119q6 0 11 -4.5t5 -11.5zM768 1280q-130 0 -248.5 -51t-204 -136.5t-136.5 -204t-51 -248.5t51 -248.5t136.5 -204t204 -136.5t248.5 - [...]
+<glyph unicode="&#xf1fa;" d="M972 761q0 108 -53.5 169t-147.5 61q-63 0 -124 -30.5t-110 -84.5t-79.5 -137t-30.5 -180q0 -112 53.5 -173t150.5 -61q96 0 176 66.5t122.5 166t42.5 203.5zM1536 640q0 -111 -37 -197t-98.5 -135t-131.5 -74.5t-145 -27.5q-6 0 -15.5 -0.5t-16.5 -0.5q-95 0 -142 53 q-28 33 -33 83q-52 -66 -131.5 -110t-173.5 -44q-161 0 -249.5 95.5t-88.5 269.5q0 157 66 290t179 210.5t246 77.5q87 0 155 -35.5t106 -99.5l2 19l11 56q1 6 5.5 12t9.5 6h118q5 0 13 -11q5 -5 3 -16l-120 -614q-5 -24 -5 -48q0  [...]
+<glyph unicode="&#xf1fb;" horiz-adv-x="1792" d="M1698 1442q94 -94 94 -226.5t-94 -225.5l-225 -223l104 -104q10 -10 10 -23t-10 -23l-210 -210q-10 -10 -23 -10t-23 10l-105 105l-603 -603q-37 -37 -90 -37h-203l-256 -128l-64 64l128 256v203q0 53 37 90l603 603l-105 105q-10 10 -10 23t10 23l210 210q10 10 23 10 t23 -10l104 -104l223 225q93 94 225.5 94t226.5 -94zM512 64l576 576l-192 192l-576 -576v-192h192z" />
+<glyph unicode="&#xf1fc;" horiz-adv-x="1792" d="M1615 1536q70 0 122.5 -46.5t52.5 -116.5q0 -63 -45 -151q-332 -629 -465 -752q-97 -91 -218 -91q-126 0 -216.5 92.5t-90.5 219.5q0 128 92 212l638 579q59 54 130 54zM706 502q39 -76 106.5 -130t150.5 -76l1 -71q4 -213 -129.5 -347t-348.5 -134q-123 0 -218 46.5 t-152.5 127.5t-86.5 183t-29 220q7 -5 41 -30t62 -44.5t59 -36.5t46 -17q41 0 55 37q25 66 57.5 112.5t69.5 76t88 47.5t103 25.5t125 10.5z" />
+<glyph unicode="&#xf1fd;" horiz-adv-x="1792" d="M1792 128v-384h-1792v384q45 0 85 14t59 27.5t47 37.5q30 27 51.5 38t56.5 11t55.5 -11t52.5 -38q29 -25 47 -38t58 -27t86 -14q45 0 85 14.5t58 27t48 37.5q21 19 32.5 27t31 15t43.5 7q35 0 56.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14t85 14t59 27.5t47 37.5 q30 27 51.5 38t56.5 11q34 0 55.5 -11t51.5 -38q28 -24 47 -37.5t59 -27.5t85 -14zM1792 448v-192q-35 0 -55.5 11t-52.5 38q-29 25 -47 38t-58 27t-85 14q-46 0 -86 -14t-58 -27t-47 -38q-22 -19 -33 -27t-3 [...]
+<glyph unicode="&#xf1fe;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1664 1024l256 -896h-1664v576l448 576l576 -576z" />
+<glyph unicode="&#xf200;" horiz-adv-x="1792" d="M768 646l546 -546q-106 -108 -247.5 -168t-298.5 -60q-209 0 -385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103v-762zM955 640h773q0 -157 -60 -298.5t-168 -247.5zM1664 768h-768v768q209 0 385.5 -103t279.5 -279.5t103 -385.5z" />
+<glyph unicode="&#xf201;" horiz-adv-x="2048" d="M2048 0v-128h-2048v1536h128v-1408h1920zM1920 1248v-435q0 -21 -19.5 -29.5t-35.5 7.5l-121 121l-633 -633q-10 -10 -23 -10t-23 10l-233 233l-416 -416l-192 192l585 585q10 10 23 10t23 -10l233 -233l464 464l-121 121q-16 16 -7.5 35.5t29.5 19.5h435q14 0 23 -9 t9 -23z" />
+<glyph unicode="&#xf202;" horiz-adv-x="1792" d="M1292 832q0 -6 10 -41q10 -29 25 -49.5t41 -34t44 -20t55 -16.5q325 -91 325 -332q0 -146 -105.5 -242.5t-254.5 -96.5q-59 0 -111.5 18.5t-91.5 45.5t-77 74.5t-63 87.5t-53.5 103.5t-43.5 103t-39.5 106.5t-35.5 95q-32 81 -61.5 133.5t-73.5 96.5t-104 64t-142 20 q-96 0 -183 -55.5t-138 -144.5t-51 -185q0 -160 106.5 -279.5t263.5 -119.5q177 0 258 95q56 63 83 116l84 -152q-15 -34 -44 -70l1 -1q-131 -152 -388 -152q-147 0 -269.5 79t-190.5 207.5t-68 274.5q0 105 43. [...]
+<glyph unicode="&#xf203;" d="M1432 484q0 173 -234 239q-35 10 -53 16.5t-38 25t-29 46.5q0 2 -2 8.5t-3 12t-1 7.5q0 36 24.5 59.5t60.5 23.5q54 0 71 -15h-1q20 -15 39 -51l93 71q-39 54 -49 64q-33 29 -67.5 39t-85.5 10q-80 0 -142 -57.5t-62 -137.5q0 -7 2 -23q16 -96 64.5 -140t148.5 -73 q29 -8 49 -15.5t45 -21.5t38.5 -34.5t13.5 -46.5v-5q1 -58 -40.5 -93t-100.5 -35q-97 0 -167 144q-23 47 -51.5 121.5t-48 125.5t-54 110.5t-74 95.5t-103.5 60.5t-147 24.5q-101 0 -192 -56t-144 -148t-50 -192v-1q4 -108 50.5 -199t [...]
+<glyph unicode="&#xf204;" horiz-adv-x="2048" d="M1152 640q0 104 -40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5t198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM1920 640q0 104 -40.5 198.5 t-109.5 163.5t-163.5 109.5t-198.5 40.5h-386q119 -90 188.5 -224t69.5 -288t-69.5 -288t-188.5 -224h386q104 0 198.5 40.5t163.5 109.5t109.5 163.5t40.5 198.5zM2048 640q0 -130 -51 -248.5t-136.5 -204t-204 -13 [...]
+<glyph unicode="&#xf205;" horiz-adv-x="2048" d="M0 640q0 130 51 248.5t136.5 204t204 136.5t248.5 51h768q130 0 248.5 -51t204 -136.5t136.5 -204t51 -248.5t-51 -248.5t-136.5 -204t-204 -136.5t-248.5 -51h-768q-130 0 -248.5 51t-204 136.5t-136.5 204t-51 248.5zM1408 128q104 0 198.5 40.5t163.5 109.5 t109.5 163.5t40.5 198.5t-40.5 198.5t-109.5 163.5t-163.5 109.5t-198.5 40.5t-198.5 -40.5t-163.5 -109.5t-109.5 -163.5t-40.5 -198.5t40.5 -198.5t109.5 -163.5t163.5 -109.5t198.5 -40.5z" />
+<glyph unicode="&#xf206;" horiz-adv-x="2304" d="M762 384h-314q-40 0 -57.5 35t6.5 67l188 251q-65 31 -137 31q-132 0 -226 -94t-94 -226t94 -226t226 -94q115 0 203 72.5t111 183.5zM576 512h186q-18 85 -75 148zM1056 512l288 384h-480l-99 -132q105 -103 126 -252h165zM2176 448q0 132 -94 226t-226 94 q-60 0 -121 -24l174 -260q15 -23 10 -49t-27 -40q-15 -11 -36 -11q-35 0 -53 29l-174 260q-93 -95 -93 -225q0 -132 94 -226t226 -94t226 94t94 226zM2304 448q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 3 [...]
+<glyph unicode="&#xf207;" d="M384 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1408 320q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5zM1362 716l-72 384q-5 23 -22.5 37.5t-40.5 14.5 h-918q-23 0 -40.5 -14.5t-22.5 -37.5l-72 -384q-5 -30 14 -53t49 -23h1062q30 0 49 23t14 53zM1136 1328q0 20 -14 34t-34 14h-640q-20 0 -34 -14t-14 -34t14 -34t34 -14h640q20 0 34 14t14 34zM1536 603v-603h-128v-128q0 -53 - [...]
+<glyph unicode="&#xf208;" horiz-adv-x="2048" d="M1463 704q0 -35 -25 -60.5t-61 -25.5h-702q-36 0 -61 25.5t-25 60.5t25 60.5t61 25.5h702q36 0 61 -25.5t25 -60.5zM1677 704q0 86 -23 170h-982q-36 0 -61 25t-25 60q0 36 25 61t61 25h908q-88 143 -235 227t-320 84q-177 0 -327.5 -87.5t-238 -237.5t-87.5 -327 q0 -86 23 -170h982q36 0 61 -25t25 -60q0 -36 -25 -61t-61 -25h-908q88 -143 235.5 -227t320.5 -84q132 0 253 51.5t208 139t139 208t52 253.5zM2048 959q0 -35 -25 -60t-61 -25h-131q17 -85 17 -170q0 -167 -65.5  [...]
+<glyph unicode="&#xf209;" horiz-adv-x="1280" d="M953 1158l-114 -328l117 -21q165 451 165 518q0 56 -38 56q-57 0 -130 -225zM654 471l33 -88q37 42 71 67l-33 5.5t-38.5 7t-32.5 8.5zM362 1367q0 -98 159 -521q18 10 49 10q15 0 75 -5l-121 351q-75 220 -123 220q-19 0 -29 -17.5t-10 -37.5zM283 608q0 -36 51.5 -119 t117.5 -153t100 -70q14 0 25.5 13t11.5 27q0 24 -32 102q-13 32 -32 72t-47.5 89t-61.5 81t-62 32q-20 0 -45.5 -27t-25.5 -47zM125 273q0 -41 25 -104q59 -145 183.5 -227t281.5 -82q227 0 382 170q152 169  [...]
+<glyph unicode="&#xf20a;" horiz-adv-x="2048" d="M785 528h207q-14 -158 -98.5 -248.5t-214.5 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-203q-5 64 -35.5 99t-81.5 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t40 -51.5t66 -18q95 0 109 139zM1497 528h206 q-14 -158 -98 -248.5t-214 -90.5q-162 0 -254.5 116t-92.5 316q0 194 93 311.5t233 117.5q148 0 232 -87t97 -247h-204q-4 64 -35 99t-81 35q-57 0 -88.5 -60.5t-31.5 -177.5q0 -48 5 -84t18 -69.5t39.5 -51.5t65 [...]
+<glyph unicode="&#xf20b;" d="M992 912v-496q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v496q0 112 -80 192t-192 80h-272v-1152q0 -14 -9 -23t-23 -9h-160q-14 0 -23 9t-9 23v1344q0 14 9 23t23 9h464q135 0 249 -66.5t180.5 -180.5t66.5 -249zM1376 1376v-880q0 -135 -66.5 -249t-180.5 -180.5 t-249 -66.5h-464q-14 0 -23 9t-9 23v960q0 14 9 23t23 9h160q14 0 23 -9t9 -23v-768h272q112 0 192 80t80 192v880q0 14 9 23t23 9h160q14 0 23 -9t9 -23z" />
+<glyph unicode="&#xf20c;" d="M1311 694v-114q0 -24 -13.5 -38t-37.5 -14h-202q-24 0 -38 14t-14 38v114q0 24 14 38t38 14h202q24 0 37.5 -14t13.5 -38zM821 464v250q0 53 -32.5 85.5t-85.5 32.5h-133q-68 0 -96 -52q-28 52 -96 52h-130q-53 0 -85.5 -32.5t-32.5 -85.5v-250q0 -22 21 -22h55 q22 0 22 22v230q0 24 13.5 38t38.5 14h94q24 0 38 -14t14 -38v-230q0 -22 21 -22h54q22 0 22 22v230q0 24 14 38t38 14h97q24 0 37.5 -14t13.5 -38v-230q0 -22 22 -22h55q21 0 21 22zM1410 560v154q0 53 -33 85.5t-86 32.5h-264q-53 0 -8 [...]
+<glyph unicode="&#xf20d;" d="M915 450h-294l147 551zM1001 128h311l-324 1024h-440l-324 -1024h311l383 314zM1536 1120v-960q0 -118 -85 -203t-203 -85h-960q-118 0 -203 85t-85 203v960q0 118 85 203t203 85h960q118 0 203 -85t85 -203z" />
+<glyph unicode="&#xf20e;" horiz-adv-x="2048" d="M2048 641q0 -21 -13 -36.5t-33 -19.5l-205 -356q3 -9 3 -18q0 -20 -12.5 -35.5t-32.5 -19.5l-193 -337q3 -8 3 -16q0 -23 -16.5 -40t-40.5 -17q-25 0 -41 18h-400q-17 -20 -43 -20t-43 20h-399q-17 -20 -43 -20q-23 0 -40 16.5t-17 40.5q0 8 4 20l-193 335 q-20 4 -32.5 19.5t-12.5 35.5q0 9 3 18l-206 356q-20 5 -32.5 20.5t-12.5 35.5q0 21 13.5 36.5t33.5 19.5l199 344q0 1 -0.5 3t-0.5 3q0 36 34 51l209 363q-4 10 -4 18q0 24 17 40.5t40 16.5q26 0 44 -21h396q16 21 43 21t [...]
+<glyph unicode="&#xf210;" d="M0 856q0 131 91.5 226.5t222.5 95.5h742l352 358v-1470q0 -132 -91.5 -227t-222.5 -95h-780q-131 0 -222.5 95t-91.5 227v790zM1232 102l-176 180v425q0 46 -32 79t-78 33h-484q-46 0 -78 -33t-32 -79v-492q0 -46 32.5 -79.5t77.5 -33.5h770z" />
+<glyph unicode="&#xf211;" d="M934 1386q-317 -121 -556 -362.5t-358 -560.5q-20 89 -20 176q0 208 102.5 384.5t278.5 279t384 102.5q82 0 169 -19zM1203 1267q93 -65 164 -155q-389 -113 -674.5 -400.5t-396.5 -676.5q-93 72 -155 162q112 386 395 671t667 399zM470 -67q115 356 379.5 622t619.5 384 q40 -92 54 -195q-292 -120 -516 -345t-343 -518q-103 14 -194 52zM1536 -125q-193 50 -367 115q-135 -84 -290 -107q109 205 274 370.5t369 275.5q-21 -152 -101 -284q65 -175 115 -370z" />
+<glyph unicode="&#xf212;" horiz-adv-x="2048" d="M1893 1144l155 -1272q-131 0 -257 57q-200 91 -393 91q-226 0 -374 -148q-148 148 -374 148q-193 0 -393 -91q-128 -57 -252 -57h-5l155 1272q224 127 482 127q233 0 387 -106q154 106 387 106q258 0 482 -127zM1398 157q129 0 232 -28.5t260 -93.5l-124 1021 q-171 78 -368 78q-224 0 -374 -141q-150 141 -374 141q-197 0 -368 -78l-124 -1021q105 43 165.5 65t148.5 39.5t178 17.5q202 0 374 -108q172 108 374 108zM1438 191l-55 907q-211 -4 -359 -155q-152 155 -374 155q-17 [...]
+<glyph unicode="&#xf213;" horiz-adv-x="2048" d="M1500 165v733q0 21 -15 36t-35 15h-93q-20 0 -35 -15t-15 -36v-733q0 -20 15 -35t35 -15h93q20 0 35 15t15 35zM1216 165v531q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-531q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM924 165v429q0 20 -15 35t-35 15h-101 q-20 0 -35 -15t-15 -35v-429q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM632 165v362q0 20 -15 35t-35 15h-101q-20 0 -35 -15t-15 -35v-362q0 -20 15 -35t35 -15h101q20 0 35 15t15 35zM2048 311q0 -166 -118 - [...]
+<glyph unicode="&#xf214;" d="M0 1536h1536v-1392l-776 -338l-760 338v1392zM1436 209v926h-1336v-926l661 -294zM1436 1235v201h-1336v-201h1336zM181 937v-115h-37v115h37zM181 789v-115h-37v115h37zM181 641v-115h-37v115h37zM181 493v-115h-37v115h37zM181 345v-115h-37v115h37zM207 202l15 34 l105 -47l-15 -33zM343 142l15 34l105 -46l-15 -34zM478 82l15 34l105 -46l-15 -34zM614 23l15 33l104 -46l-15 -34zM797 10l105 46l15 -33l-105 -47zM932 70l105 46l15 -34l-105 -46zM1068 130l105 46l15 -34l-105 -46zM1203 189l10 [...]
+<glyph unicode="&#xf215;" horiz-adv-x="2048" d="M863 504q0 112 -79.5 191.5t-191.5 79.5t-191 -79.5t-79 -191.5t79 -191t191 -79t191.5 79t79.5 191zM1726 505q0 112 -79 191t-191 79t-191.5 -79t-79.5 -191q0 -113 79.5 -192t191.5 -79t191 79.5t79 191.5zM2048 1314v-1348q0 -44 -31.5 -75.5t-76.5 -31.5h-1832 q-45 0 -76.5 31.5t-31.5 75.5v1348q0 44 31.5 75.5t76.5 31.5h431q44 0 76 -31.5t32 -75.5v-161h754v161q0 44 32 75.5t76 31.5h431q45 0 76.5 -31.5t31.5 -75.5z" />
+<glyph unicode="&#xf216;" horiz-adv-x="2048" d="M1430 953zM1690 749q148 0 253 -98.5t105 -244.5q0 -157 -109 -261.5t-267 -104.5q-85 0 -162 27.5t-138 73.5t-118 106t-109 126.5t-103.5 132.5t-108.5 126t-117 106t-136 73.5t-159 27.5q-154 0 -251.5 -91.5t-97.5 -244.5q0 -157 104 -250t263 -93q100 0 208 37.5 t193 98.5q5 4 21 18.5t30 24t22 9.5q14 0 24.5 -10.5t10.5 -24.5q0 -24 -60 -77q-101 -88 -234.5 -142t-260.5 -54q-133 0 -245.5 58t-180 165t-67.5 241q0 205 141.5 341t347.5 136q120 0 226.5 -43.5t185.5 - [...]
+<glyph unicode="&#xf217;" horiz-adv-x="1664" d="M1216 832q0 26 -19 45t-45 19h-128v128q0 26 -19 45t-45 19t-45 -19t-19 -45v-128h-128q-26 0 -45 -19t-19 -45t19 -45t45 -19h128v-128q0 -26 19 -45t45 -19t45 19t19 45v128h128q26 0 45 19t19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1  [...]
+<glyph unicode="&#xf218;" horiz-adv-x="1792" d="M1280 832q0 26 -19 45t-45 19t-45 -19l-147 -146v293q0 26 -19 45t-45 19t-45 -19t-19 -45v-293l-147 146q-19 19 -45 19t-45 -19t-19 -45t19 -45l256 -256q19 -19 45 -19t45 19l256 256q19 19 19 45zM640 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5 t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1536 0q0 -53 -37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5t37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5zM1664 1088v-512q0 -24 -16 -42.5t-41 -21.5l-1044 -122q1 [...]
+<glyph unicode="&#xf219;" horiz-adv-x="2048" d="M212 768l623 -665l-300 665h-323zM1024 -4l349 772h-698zM538 896l204 384h-262l-288 -384h346zM1213 103l623 665h-323zM683 896h682l-204 384h-274zM1510 896h346l-288 384h-262zM1651 1382l384 -512q14 -18 13 -41.5t-17 -40.5l-960 -1024q-18 -20 -47 -20t-47 20 l-960 1024q-16 17 -17 40.5t13 41.5l384 512q18 26 51 26h1152q33 0 51 -26z" />
+<glyph unicode="&#xf21a;" horiz-adv-x="2048" d="M1811 -19q19 19 45 19t45 -19l128 -128l-90 -90l-83 83l-83 -83q-18 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-83 83l-83 -83 q-19 -19 -45 -19t-45 19l-83 83l-83 -83q-19 -19 -45 -19t-45 19l-128 128l90 90l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 45 19t45 -19l83 -83l83 83q19 19 4 [...]
+<glyph unicode="&#xf21b;" d="M576 0l96 448l-96 128l-128 64zM832 0l128 640l-128 -64l-96 -128zM992 1010q-2 4 -4 6q-10 8 -96 8q-70 0 -167 -19q-7 -2 -21 -2t-21 2q-97 19 -167 19q-86 0 -96 -8q-2 -2 -4 -6q2 -18 4 -27q2 -3 7.5 -6.5t7.5 -10.5q2 -4 7.5 -20.5t7 -20.5t7.5 -17t8.5 -17t9 -14 t12 -13.5t14 -9.5t17.5 -8t20.5 -4t24.5 -2q36 0 59 12.5t32.5 30t14.5 34.5t11.5 29.5t17.5 12.5h12q11 0 17.5 -12.5t11.5 -29.5t14.5 -34.5t32.5 -30t59 -12.5q13 0 24.5 2t20.5 4t17.5 8t14 9.5t12 13.5t9 14t8.5 17t7.5 17t7 [...]
+<glyph unicode="&#xf21c;" horiz-adv-x="2304" d="M2301 500q12 -103 -22 -198.5t-99 -163.5t-158.5 -106t-196.5 -31q-161 11 -279.5 125t-134.5 274q-12 111 27.5 210.5t118.5 170.5l-71 107q-96 -80 -151 -194t-55 -244q0 -27 -18.5 -46.5t-45.5 -19.5h-256h-69q-23 -164 -149 -274t-294 -110q-185 0 -316.5 131.5 t-131.5 316.5t131.5 316.5t316.5 131.5q76 0 152 -27l24 45q-123 110 -304 110h-64q-26 0 -45 19t-19 45t19 45t45 19h128q78 0 145 -13.5t116.5 -38.5t71.5 -39.5t51 -36.5h512h115l-85 128h-222q-30 0 -49 22.5 [...]
+<glyph unicode="&#xf21d;" d="M1408 0q0 -63 -61.5 -113.5t-164 -81t-225 -46t-253.5 -15.5t-253.5 15.5t-225 46t-164 81t-61.5 113.5q0 49 33 88.5t91 66.5t118 44.5t131 29.5q26 5 48 -10.5t26 -41.5q5 -26 -10.5 -48t-41.5 -26q-58 -10 -106 -23.5t-76.5 -25.5t-48.5 -23.5t-27.5 -19.5t-8.5 -12 q3 -11 27 -26.5t73 -33t114 -32.5t160.5 -25t201.5 -10t201.5 10t160.5 25t114 33t73 33.5t27 27.5q-1 4 -8.5 11t-27.5 19t-48.5 23.5t-76.5 25t-106 23.5q-26 4 -41.5 26t-10.5 48q4 26 26 41.5t48 10.5q71 -12 131 -29.5t118 - [...]
+<glyph unicode="&#xf21e;" horiz-adv-x="1792" d="M1280 512h305q-5 -6 -10 -10.5t-9 -7.5l-3 -4l-623 -600q-18 -18 -44 -18t-44 18l-624 602q-5 2 -21 20h369q22 0 39.5 13.5t22.5 34.5l70 281l190 -667q6 -20 23 -33t39 -13q21 0 38 13t23 33l146 485l56 -112q18 -35 57 -35zM1792 940q0 -145 -103 -300h-369l-111 221 q-8 17 -25.5 27t-36.5 8q-45 -5 -56 -46l-129 -430l-196 686q-6 20 -23.5 33t-39.5 13t-39 -13.5t-22 -34.5l-116 -464h-423q-103 155 -103 300q0 220 127 344t351 124q62 0 126.5 -21.5t120 -58t95.5 -68.5t [...]
+<glyph unicode="&#xf221;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292 q11 134 80.5 249t182 188t245.5 88q170 19 319 -54t236 -212t87 -306zM128 960q0 -185 131.5 -316.5t316.5 -131.5t316.5 131.5t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5z" />
+<glyph unicode="&#xf222;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h416q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-419 -420q87 -104 129.5 -236.5t30.5 -276.5q-22 -250 -200.5 -431t-428.5 -206q-163 -17 -314 39.5t-256.5 162t-162 256.5t-39.5 314q25 250 206 428.5 t431 200.5q144 12 276.5 -30.5t236.5 -129.5l419 419h-261q-14 0 -23 9t-9 23v64zM704 -128q117 0 223.5 45.5t184 123t123 184t45.5 223.5t-45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 [...]
+<glyph unicode="&#xf223;" horiz-adv-x="1280" d="M830 1220q145 -72 233.5 -210.5t88.5 -305.5q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5 t-147.5 384.5q0 167 88.5 305.5t233.5 210.5q-165 96 -228 273q-6 16 3.5 29.5t26.5 13.5h69q21 0 29 -20q44 -106 140 -171t214 -65t214 65t140 171q8 20 37 20h61q17 0 26.5 -13.5t3.5 -29.5q-63 -177 -228 -2 [...]
+<glyph unicode="&#xf224;" d="M1024 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-149 16 -270.5 103t-186.5 223.5t-53 291.5q16 204 160 353.5t347 172.5q118 14 228 -19t198 -103l255 254h-134q-14 0 -23 9t-9 23v64zM576 256q185 0 316.5 13 [...]
+<glyph unicode="&#xf225;" horiz-adv-x="1792" d="M1280 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q126 -158 126 -359q0 -221 -147.5 -384.5t-364.5 -187.5v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64 q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-217 24 -364.5 187.5t-147.5 384.5q0 201 126 359l-52 53l-101 -111q-9 -10 -22 -10.5t-23 7.5l-48 44q-10 8 -10.5 21.5t8.5 23.5l105 115l [...]
+<glyph unicode="&#xf226;" horiz-adv-x="1792" d="M1790 1007q12 -155 -52.5 -292t-186 -224t-271.5 -103v-260h224q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-224v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-512v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-224q-14 0 -23 9t-9 23v64q0 14 9 23 t23 9h224v260q-150 16 -271.5 103t-186 224t-52.5 292q17 206 164.5 356.5t352.5 169.5q206 21 377 -94q171 115 377 94q205 -19 352.5 -169.5t164.5 -356.5zM896 647q128 131 128 313t-128 313q-128 -131 -12 [...]
+<glyph unicode="&#xf227;" horiz-adv-x="1920" d="M1536 1120q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-31 -182 -166 -312t-318 -156q-210 -29 -384.5 80t-241.5 300q-117 6 -221 57.5t-177.5 133t-113.5 192.5t-32 230 q9 135 78 252t182 191.5t248 89.5q118 14 227.5 -19t198.5 -103l255 254h-134q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q59 -7 [...]
+<glyph unicode="&#xf228;" horiz-adv-x="2048" d="M1664 1504q0 14 9 23t23 9h288q26 0 45 -19t19 -45v-288q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v134l-254 -255q76 -95 107.5 -214t9.5 -247q-32 -180 -164.5 -310t-313.5 -157q-223 -34 -409 90q-117 -78 -256 -93v-132h96q14 0 23 -9t9 -23v-64q0 -14 -9 -23 t-23 -9h-96v-96q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v96h-96q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h96v132q-155 17 -279.5 109.5t-187 237.5t-39.5 307q25 187 159.5 322.5t320.5 164.5q224 34 410 -90q1 [...]
+<glyph unicode="&#xf229;" horiz-adv-x="1792" d="M1728 1536q26 0 45 -19t19 -45v-416q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v262l-229 -230l156 -156q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-156 157l-99 -100q87 -104 129.5 -236.5t30.5 -276.5q-22 -250 -200.5 -431t-428.5 -206q-163 -17 -314 39.5 t-256.5 162t-162 256.5t-39.5 314q25 250 206 428.5t431 200.5q144 12 276.5 -30.5t236.5 -129.5l99 99l-156 156q-9 10 -9 23t9 22l46 46q9 9 22 9t23 -9l156 -156l229 229h-261q-14 0 -23 9t-9 23v64q0 14 9  [...]
+<glyph unicode="&#xf22a;" horiz-adv-x="1280" d="M640 892q217 -24 364.5 -187.5t147.5 -384.5q0 -167 -87 -306t-236 -212t-319 -54q-133 15 -245.5 88t-182 188t-80.5 249q-12 155 52.5 292t186 224t271.5 103v132h-160q-14 0 -23 9t-9 23v64q0 14 9 23t23 9h160v165l-92 -92q-10 -9 -23 -9t-22 9l-46 46q-9 9 -9 22 t9 23l202 201q19 19 45 19t45 -19l202 -201q9 -10 9 -23t-9 -22l-46 -46q-9 -9 -22 -9t-23 9l-92 92v-165h160q14 0 23 -9t9 -23v-64q0 -14 -9 -23t-23 -9h-160v-132zM576 -128q185 0 316.5 131.5t131.5 316.5t [...]
+<glyph unicode="&#xf22b;" horiz-adv-x="2048" d="M2029 685q19 -19 19 -45t-19 -45l-294 -294q-9 -10 -22.5 -10t-22.5 10l-45 45q-10 9 -10 22.5t10 22.5l185 185h-294v-224q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v224h-131q-12 -119 -67 -226t-139 -183.5t-196.5 -121.5t-234.5 -45q-180 0 -330.5 91t-234.5 247 t-74 337q8 162 94 300t226.5 219.5t302.5 85.5q166 4 310.5 -71.5t235.5 -208.5t107 -296h131v224q0 14 9 23t23 9h64q14 0 23 -9t9 -23v-224h294l-185 185q-10 9 -10 22.5t10 22.5l45 45q9 10 22.5 10t22.5 - [...]
+<glyph unicode="&#xf22c;" horiz-adv-x="1280" d="M1152 960q0 -221 -147.5 -384.5t-364.5 -187.5v-612q0 -14 -9 -23t-23 -9h-64q-14 0 -23 9t-9 23v612q-217 24 -364.5 187.5t-147.5 384.5q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5zM576 512q185 0 316.5 131.5 t131.5 316.5t-131.5 316.5t-316.5 131.5t-316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf22d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf22e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf22f;" horiz-adv-x="1792" />
+<glyph unicode="&#xf230;" d="M1451 1408q35 0 60 -25t25 -60v-1366q0 -35 -25 -60t-60 -25h-391v595h199l30 232h-229v148q0 56 23.5 84t91.5 28l122 1v207q-63 9 -178 9q-136 0 -217.5 -80t-81.5 -226v-171h-200v-232h200v-595h-735q-35 0 -60 25t-25 60v1366q0 35 25 60t60 25h1366z" />
+<glyph unicode="&#xf231;" horiz-adv-x="1280" d="M0 939q0 108 37.5 203.5t103.5 166.5t152 123t185 78t202 26q158 0 294 -66.5t221 -193.5t85 -287q0 -96 -19 -188t-60 -177t-100 -149.5t-145 -103t-189 -38.5q-68 0 -135 32t-96 88q-10 -39 -28 -112.5t-23.5 -95t-20.5 -71t-26 -71t-32 -62.5t-46 -77.5t-62 -86.5 l-14 -5l-9 10q-15 157 -15 188q0 92 21.5 206.5t66.5 287.5t52 203q-32 65 -32 169q0 83 52 156t132 73q61 0 95 -40.5t34 -102.5q0 -66 -44 -191t-44 -187q0 -63 45 -104.5t109 -41.5q55 0 102 25t78.5 68t56 9 [...]
+<glyph unicode="&#xf232;" d="M985 562q13 0 97.5 -44t89.5 -53q2 -5 2 -15q0 -33 -17 -76q-16 -39 -71 -65.5t-102 -26.5q-57 0 -190 62q-98 45 -170 118t-148 185q-72 107 -71 194v8q3 91 74 158q24 22 52 22q6 0 18 -1.5t19 -1.5q19 0 26.5 -6.5t15.5 -27.5q8 -20 33 -88t25 -75q0 -21 -34.5 -57.5 t-34.5 -46.5q0 -7 5 -15q34 -73 102 -137q56 -53 151 -101q12 -7 22 -7q15 0 54 48.5t52 48.5zM782 32q127 0 243.5 50t200.5 134t134 200.5t50 243.5t-50 243.5t-134 200.5t-200.5 134t-243.5 50t-243.5 -50t-200.5 -134t-134 - [...]
+<glyph unicode="&#xf233;" horiz-adv-x="1792" d="M128 128h1024v128h-1024v-128zM128 640h1024v128h-1024v-128zM1696 192q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM128 1152h1024v128h-1024v-128zM1696 704q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1696 1216 q0 40 -28 68t-68 28t-68 -28t-28 -68t28 -68t68 -28t68 28t28 68zM1792 384v-384h-1792v384h1792zM1792 896v-384h-1792v384h1792zM1792 1408v-384h-1792v384h1792z" />
+<glyph unicode="&#xf234;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1664 512h352q13 0 22.5 -9.5t9.5 -22.5v-192q0 -13 -9.5 -22.5t-22.5 -9.5h-352v-352q0 -13 -9.5 -22.5t-22.5 -9.5h-192q-13 0 -22.5 9.5 t-9.5 22.5v352h-352q-13 0 -22.5 9.5t-9.5 22.5v192q0 13 9.5 22.5t22.5 9.5h352v352q0 13 9.5 22.5t22.5 9.5h192q13 0 22.5 -9.5t9.5 -22.5v-352zM928 288q0 -52 38 -90t90 -38h256v-238q-68 -50 -171 -50h [...]
+<glyph unicode="&#xf235;" horiz-adv-x="2048" d="M704 640q-159 0 -271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5zM1781 320l249 -249q9 -9 9 -23q0 -13 -9 -22l-136 -136q-9 -9 -22 -9q-14 0 -23 9l-249 249l-249 -249q-9 -9 -23 -9q-13 0 -22 9l-136 136 q-9 9 -9 22q0 14 9 23l249 249l-249 249q-9 9 -9 23q0 13 9 22l136 136q9 9 22 9q14 0 23 -9l249 -249l249 249q9 9 23 9q13 0 22 -9l136 -136q9 -9 9 -22q0 -14 -9 -23zM1283 320l-181 -181q-37 -37 -37 -91 [...]
+<glyph unicode="&#xf236;" horiz-adv-x="2048" d="M256 512h1728q26 0 45 -19t19 -45v-448h-256v256h-1536v-256h-256v1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45v-704zM832 832q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75t181 75t75 181zM2048 576v64q0 159 -112.5 271.5t-271.5 112.5h-704 q-26 0 -45 -19t-19 -45v-384h1152z" />
+<glyph unicode="&#xf237;" d="M1536 1536l-192 -448h192v-192h-274l-55 -128h329v-192h-411l-357 -832l-357 832h-411v192h329l-55 128h-274v192h192l-192 448h256l323 -768h378l323 768h256zM768 320l108 256h-216z" />
+<glyph unicode="&#xf238;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM768 192q80 0 136 56t56 136t-56 136t-136 56 t-136 -56t-56 -136t56 -136t136 -56zM1344 768v512h-1152v-512h1152z" />
+<glyph unicode="&#xf239;" d="M1088 1536q185 0 316.5 -93.5t131.5 -226.5v-896q0 -130 -125.5 -222t-305.5 -97l213 -202q16 -15 8 -35t-30 -20h-1056q-22 0 -30 20t8 35l213 202q-180 5 -305.5 97t-125.5 222v896q0 133 131.5 226.5t316.5 93.5h640zM288 224q66 0 113 47t47 113t-47 113t-113 47 t-113 -47t-47 -113t47 -113t113 -47zM704 768v512h-544v-512h544zM1248 224q66 0 113 47t47 113t-47 113t-113 47t-113 -47t-47 -113t47 -113t113 -47zM1408 768v512h-576v-512h576z" />
+<glyph unicode="&#xf23a;" horiz-adv-x="1792" d="M1792 204v-209h-642v209h134v926h-6l-314 -1135h-243l-310 1135h-8v-926h135v-209h-538v209h69q21 0 43 19.5t22 37.5v881q0 18 -22 40t-43 22h-69v209h672l221 -821h6l223 821h670v-209h-71q-19 0 -41 -22t-22 -40v-881q0 -18 21.5 -37.5t41.5 -19.5h71z" />
+<glyph unicode="&#xf23b;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23c;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23d;" horiz-adv-x="1792" />
+<glyph unicode="&#xf23e;" horiz-adv-x="1792" />
+<glyph unicode="&#xf500;" horiz-adv-x="1792" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.ttf b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.ttf
new file mode 100644
index 0000000..ed9372f
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.ttf differ
diff --git a/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff
new file mode 100644
index 0000000..8b280b9
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff differ
diff --git a/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff2 b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff2
new file mode 100644
index 0000000..3311d58
Binary files /dev/null and b/dicoogle/src/main/resources/webapp/fonts/fontawesome-webfont.woff2 differ
diff --git a/dicoogle/src/main/resources/webapp/gulpfile.js b/dicoogle/src/main/resources/webapp/gulpfile.js
new file mode 100644
index 0000000..0551422
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/gulpfile.js
@@ -0,0 +1,161 @@
+'use strict';
+
+var browserify = require('browserify');
+var buffer = require('vinyl-buffer');
+var eslint = require('gulp-eslint');
+var gulp = require('gulp');
+var gutil = require('gulp-util');
+var processhtml = require('gulp-processhtml');
+var rename = require('gulp-rename');
+var rm = require('gulp-rm');
+var sass = require('gulp-sass');
+var source = require('vinyl-source-stream');
+var sourcemaps = require('gulp-sourcemaps');
+var uglify = require('gulp-uglify');
+var watchify = require('watchify');
+
+require('core-js/fn/object/assign');
+
+var EXTERNAL_REQUIRES = [
+    'react', 'react-router', 'reflux', 'dicoogle-webcore', 'dicoogle-client',
+    'react-bootstrap', 'react-router-bootstrap', 'react-bootstrap-table', 'react-imageloader', "react-dom"];
+
+function createBrowserify(debug, watch) {
+  // set up the browserify instance on a task basis
+  var b = browserify('./js/app.js', {
+    cache: {},
+    packageCache: {},
+    extensions: ['.jsx'],
+    debug: debug,
+    transform: [
+      [
+        'babelify', {
+          presets: ['es2015', 'react']
+        }
+      ],
+      [
+        'envify', {
+          _: 'purge',
+          global: true,
+          NODE_ENV: debug ? 'development' : 'production'
+        }
+      ]
+    ]
+  });
+  if (watch) {
+    b.plugin(watchify);
+  }
+  return b.require(EXTERNAL_REQUIRES);
+}
+
+gulp.task('production-env', function() {
+    process.env.NODE_ENV = 'production';
+});
+
+gulp.task('lint', function () {
+  return gulp.src(['js/**/*.js', 'js/**/*.jsx'])
+    .pipe(eslint({
+      configFile: ".eslintrc"
+    }))
+    .pipe(eslint.format())
+    .pipe(eslint.failAfterError());
+});
+
+function handleBundlingError(e) {
+  gutil.log('' + e);
+}
+
+gulp.task('js', ['lint'], function () {
+  return createBrowserify(false, false)
+    .bundle()
+    .on('error', handleBundlingError)
+    .pipe(source('bundle.min.js'))
+    .pipe(buffer())
+    .pipe(uglify({compress: {
+      dead_code: true,
+      drop_console: true,
+      warnings: false
+      }, mangle: true}))
+    .pipe(gulp.dest('lib'));
+});
+
+gulp.task('js-debug', ['lint'], function () {
+  return createBrowserify(true, false)
+    .bundle()
+    .on('error', handleBundlingError)
+    .pipe(source('bundle.js'))
+    .pipe(buffer())
+    .pipe(sourcemaps.init({loadMaps: true}))
+    .pipe(sourcemaps.write('./'))
+    .pipe(gulp.dest('lib'));
+});
+
+gulp.task('js:watch', function () {
+
+  var b = createBrowserify(true, true);
+  b.on('update', bundle); // on any dep update, runs the bundler
+  b.on('log', gutil.log); // output build logs to terminal
+
+  function bundle() {
+    return b.bundle()
+      .on('error', handleBundlingError)
+      .pipe(source('bundle.js'))
+      .pipe(buffer())
+      .pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
+        // Add transformation tasks to the pipeline here.
+      .pipe(sourcemaps.write('./')) // writes .map file
+      .pipe(gulp.dest('lib'));
+  }
+  bundle();
+});
+
+gulp.task('html', function () {
+  // use processhtml
+  return gulp.src('index-template.html')
+    .pipe(processhtml({
+      environment: "dist",
+      strip: true
+    }))
+    .pipe(rename('index.html'))
+    .pipe(gulp.dest('.'));
+});
+
+gulp.task('html-debug', function () {
+  // use processhtml
+  return gulp.src('index-template.html')
+    .pipe(processhtml({
+      environment: "dev"
+    }))
+    .pipe(rename('index.html'))
+    .pipe(gulp.dest('.'));
+});
+
+gulp.task('css', function () {
+  // use sass
+  return gulp.src('sass/dicoogle.scss')
+    .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
+    .pipe(gulp.dest('css'));
+});
+
+gulp.task('css-debug', function () {
+  // use sass
+  return gulp.src('sass/dicoogle.scss')
+    .pipe(sourcemaps.init())
+    .pipe(sass().on('error', sass.logError))
+    .pipe(sourcemaps.write())
+    .pipe(gulp.dest('css'));
+});
+
+gulp.task('css:watch', function () {
+  gulp.watch('sass/**/*.scss', ['css-debug']);
+});
+
+gulp.task('production', ['production-env', 'js', 'html', 'css']);
+gulp.task('development', ['js-debug', 'html-debug', 'css-debug']);
+
+gulp.task( 'clean', function() {
+  return gulp.src(['lib/bundle.*', 'css/dicoogle.css*', 'index.html'], { read: false })
+    .pipe( rm() );
+});
+
+gulp.task('default', ['production']);
diff --git a/dicoogle/src/main/resources/webapp/index-template.html b/dicoogle/src/main/resources/webapp/index-template.html
new file mode 100644
index 0000000..a5a600a
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/index-template.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<!--[if lt IE 7 ]> <html class="ie6"> <![endif]-->
+<!--[if IE 7 ]>    <html class="ie7"> <![endif]-->
+<!--[if IE 8 ]>    <html class="ie8"> <![endif]-->
+<!--[if IE 9 ]>    <html class="ie9"> <![endif]-->
+<!--[if (gt IE 9)|!(IE)]><!--> <html class="" lang="en"> <!--<![endif]-->
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta name="description" content="Dicoogle Web Application">
+    <meta name="author" content="Universidade de Aveiro, DETI/IEETA, Bioinformatics Group (http://bioinformatics.ua.pt/)">
+    <title>Dicoogle</title>
+    <link rel="shortcut icon" href="assets/favicon.ico">
+    <!-- Bootstrap core CSS -->
+    <link href="bootstrap/css/bootstrap.css" rel="stylesheet">
+    <link rel="stylesheet" href="css/font-awesome.min.css">
+    <!-- Bootstrap theme -->
+    <link href="bootstrap/css/bootstrap-theme.min.css" rel="stylesheet">
+    <!-- Custom styles for this template -->
+    <!-- <link href="css/theme.css" rel="stylesheet"> -->
+
+    <link href='css/fonts-google.css' rel='stylesheet' type='text/css'>
+
+    <!-- Custom CSS -->
+    <link href="css/simple-sidebar.css" rel="stylesheet">
+    <link href="css/loaders.min.css" rel="stylesheet">
+
+    <link rel="stylesheet" href="css/react-bootstrap-table.min.css">
+
+    <link rel="stylesheet" href="css/jquery-ui.css">
+
+     <!--Custom JS -->
+     <!--
+    <script src="lib/es6-shim.js"></script>
+    <script src="lib/es6-sham.js"></script>
+    <script src="lib/document-register-element.js"></script>
+    -->
+
+     <!-- Keep dicoogle sass generated css always the last one-->
+    <link href="css/dicoogle.css" rel="stylesheet">
+
+</head>
+<body>
+  <div id="react-container">
+  </div>
+
+    <!-- /container -->
+    <!-- Bootstrap core JavaScript
+    ================================================== -->
+    <!-- Placed at the end of the document so the pages load faster -->
+
+<!--[if (gt IE 9)|!(IE)]><!-->
+<!-- build:remove:dist -->
+<script src="lib/bundle.js"></script>
+<!--/build-->
+<!-- build:remove:dev -->
+<script src="lib/bundle.min.js"></script>
+<!--/build-->
+<!--<![endif]-->
+
+<!--[if lte IE 9]>
+<script>
+  // exhibit a warning on old IE browsers
+  var warningHtml = document.createElement('div');
+  warningHtml.innerHTML = '<div class="topbar"><div class="text-center" style="color:#EECD0C;font-size:large;"><b>Your Internet browser is not supported by Dicoogle! Please update your browser.</b></div></div><div style="display:flex;"></div>';
+  document.body.appendChild(warningHtml);
+</script>
+<![endif]-->
+</body>
+</html>
diff --git a/dicoogle/src/main/resources/webapp/js/actions/dumpActions.js b/dicoogle/src/main/resources/webapp/js/actions/dumpActions.js
new file mode 100644
index 0000000..72a2452
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/dumpActions.js
@@ -0,0 +1,4 @@
+import Reflux from 'reflux';
+export const DumpActions = {
+  get: Reflux.createAction()
+}
diff --git a/dicoogle/src/main/resources/webapp/js/actions/exportActions.js b/dicoogle/src/main/resources/webapp/js/actions/exportActions.js
new file mode 100644
index 0000000..5eada08
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/exportActions.js
@@ -0,0 +1,6 @@
+import Reflux from 'reflux';
+const ExportActions = exports;
+ExportActions.getFieldList = Reflux.createAction();
+ExportActions.exportCSV = Reflux.createAction();
+
+export { ExportActions };
diff --git a/dicoogle/src/main/resources/webapp/js/actions/indexStatusAction.js b/dicoogle/src/main/resources/webapp/js/actions/indexStatusAction.js
new file mode 100644
index 0000000..aff0862
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/indexStatusAction.js
@@ -0,0 +1,8 @@
+import Reflux from 'reflux';
+const IndexStatusActions = exports;
+IndexStatusActions.get = Reflux.createAction();
+IndexStatusActions.start = Reflux.createAction();
+IndexStatusActions.stop = Reflux.createAction();
+IndexStatusActions.close = Reflux.createAction();
+
+export { IndexStatusActions };
diff --git a/dicoogle/src/main/resources/webapp/js/actions/indexerActions.js b/dicoogle/src/main/resources/webapp/js/actions/indexerActions.js
new file mode 100644
index 0000000..053f8b1
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/indexerActions.js
@@ -0,0 +1,5 @@
+import Reflux from 'reflux';
+const IndexerActions = exports;
+IndexerActions.get = Reflux.createAction();
+
+export { IndexerActions };
diff --git a/dicoogle/src/main/resources/webapp/js/actions/loggerActions.js b/dicoogle/src/main/resources/webapp/js/actions/loggerActions.js
new file mode 100644
index 0000000..e18bfc7
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/loggerActions.js
@@ -0,0 +1,4 @@
+import Reflux from 'reflux';
+export const LoggerActions = {
+  get: Reflux.createAction()
+}
diff --git a/dicoogle/src/main/resources/webapp/js/actions/providersActions.js b/dicoogle/src/main/resources/webapp/js/actions/providersActions.js
new file mode 100644
index 0000000..fe8949d
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/providersActions.js
@@ -0,0 +1,4 @@
+import Reflux from 'reflux';
+export const ProvidersActions = {
+  get: Reflux.createAction()
+};
diff --git a/dicoogle/src/main/resources/webapp/js/actions/resultSelectAction.js b/dicoogle/src/main/resources/webapp/js/actions/resultSelectAction.js
new file mode 100644
index 0000000..6e5dd28
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/resultSelectAction.js
@@ -0,0 +1,13 @@
+import Reflux from 'reflux';
+
+/**
+ * The goal of these actions is to handle result batches.
+ */
+
+export const select = Reflux.createAction();
+export const unSelect = Reflux.createAction();
+export const clear = Reflux.createAction();
+export const get = Reflux.createAction();
+export const level = Reflux.createAction();
+
+export default { select, clear, get, level, unSelect };
diff --git a/dicoogle/src/main/resources/webapp/js/actions/searchActions.js b/dicoogle/src/main/resources/webapp/js/actions/searchActions.js
new file mode 100644
index 0000000..ad8b631
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/searchActions.js
@@ -0,0 +1,7 @@
+import Reflux from 'reflux';
+const ActionCreators = exports;
+ActionCreators.search = Reflux.createAction();
+ActionCreators.unindex = Reflux.createAction();
+ActionCreators.remove = Reflux.createAction();
+//ActionCreators.advancedOptionsChange = Reflux.createAction();
+export { ActionCreators };
diff --git a/dicoogle/src/main/resources/webapp/js/actions/servicesAction.js b/dicoogle/src/main/resources/webapp/js/actions/servicesAction.js
new file mode 100644
index 0000000..00fb3ac
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/servicesAction.js
@@ -0,0 +1,14 @@
+import Reflux from 'reflux';
+const ServiceAction = {};
+ServiceAction.getStorage = Reflux.createAction();
+ServiceAction.getQuery = Reflux.createAction();
+ServiceAction.setStorage = Reflux.createAction();
+ServiceAction.setStoragePort = Reflux.createAction();
+ServiceAction.setQuery = Reflux.createAction();
+ServiceAction.setQueryPort = Reflux.createAction();
+ServiceAction.setStorageAutostart = Reflux.createAction();
+ServiceAction.setQueryAutostart = Reflux.createAction();
+ServiceAction.getQuerySettings = Reflux.createAction();
+ServiceAction.saveQuerySettings = Reflux.createAction();
+
+export default ServiceAction;
diff --git a/dicoogle/src/main/resources/webapp/js/actions/storageActions.js b/dicoogle/src/main/resources/webapp/js/actions/storageActions.js
new file mode 100644
index 0000000..850bb95
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/storageActions.js
@@ -0,0 +1,6 @@
+import Reflux from 'reflux';
+export const StorageActions = {
+  get: Reflux.createAction(),
+  add: Reflux.createAction(),
+  remove: Reflux.createAction()
+};
diff --git a/dicoogle/src/main/resources/webapp/js/actions/transferActions.js b/dicoogle/src/main/resources/webapp/js/actions/transferActions.js
new file mode 100644
index 0000000..f14b25d
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/transferActions.js
@@ -0,0 +1,7 @@
+import Reflux from 'reflux';
+export const TransferActions = {
+  get: Reflux.createAction(),
+  set: Reflux.createAction(),
+  selectAll: Reflux.createAction(),
+  unSelectAll: Reflux.createAction()
+};
diff --git a/dicoogle/src/main/resources/webapp/js/actions/userActions.js b/dicoogle/src/main/resources/webapp/js/actions/userActions.js
new file mode 100644
index 0000000..53a0ab0
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/userActions.js
@@ -0,0 +1,6 @@
+import Reflux from 'reflux';
+export const UserActions = {
+  login: Reflux.createAction(),
+  logout: Reflux.createAction(),
+  isLoggedIn: Reflux.createAction()
+};
diff --git a/dicoogle/src/main/resources/webapp/js/actions/versionAction.js b/dicoogle/src/main/resources/webapp/js/actions/versionAction.js
new file mode 100644
index 0000000..f992319
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/actions/versionAction.js
@@ -0,0 +1,5 @@
+import Reflux from 'reflux';
+
+export const VersionActions = {
+  get: Reflux.createAction()
+};
diff --git a/dicoogle/src/main/resources/webapp/js/app.js b/dicoogle/src/main/resources/webapp/js/app.js
new file mode 100644
index 0000000..f21fa3c
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/app.js
@@ -0,0 +1,189 @@
+import $ from 'jquery';
+import React, {PropTypes} from 'react';
+import ReactDOM from 'react-dom';
+import Sidebar from './components/sidebar';
+import {Endpoints} from './constants/endpoints';
+import dicoogleClient from 'dicoogle-client';
+import Webcore from 'dicoogle-webcore';
+
+import {Router, Route, IndexRoute} from 'react-router';
+
+import {Search} from './components/search/searchView';
+import {SearchResultView} from './components/search/searchResultView';
+import {IndexStatusView} from './components/indexer/IndexStatusView';
+import {ManagementView} from './components/management/managementView';
+import {DirectImageView} from './components/direct/directImageView';
+import {DirectDumpView} from './components/direct/directDumpView';
+import PluginView from './components/plugin/pluginView';
+import AboutView from './components/about/aboutView';
+import LoadingView from './components/login/loadingView';
+import LoginView from './components/login/loginView';
+import { hashHistory /*, browserHistory*/ } from 'react-router'
+import {UserActions} from './actions/userActions';
+import {UserStore} from './stores/userStore';
+
+require('core-js/shim');
+
+require('jquery-ui');
+
+window.jQuery = $; // Bootstrap won't work without this hack. browserify-shim didn't help either
+require('bootstrap');
+
+class App extends React.Component {
+  static get contextTypes () {
+    return {
+			router: PropTypes.object.isRequired,
+			location: React.PropTypes.object
+
+		};
+  }
+
+	constructor(props) {
+		super(props);
+		this.pluginsFetched = false;
+		this.state = {
+			pluginMenuItems: []
+		};
+		this.logout = this.logout.bind(this);
+	}
+
+	/**
+	 * @param {packageJSON|packageJSON[]} plugins
+	 */
+	onMenuPlugin(packages) {
+		const {pluginMenuItems} = this.state;
+
+		this.setState({
+			pluginMenuItems: pluginMenuItems.concat(packages.map(pkg => ({
+					value: pkg.name,
+					caption: pkg.dicoogle.caption || pkg.name,
+					isPlugin: true,
+					icon: 'fa fa-plug'
+				})))
+		});
+	}
+
+	componentWillMount()
+	{
+		UserStore.listen(this.fetchPlugins.bind(this));
+
+		const Dicoogle = dicoogleClient(Endpoints.base);
+		if (localStorage.token) {
+			Dicoogle.setToken(localStorage.token);
+		}
+		if (this.props.location.pathname=='/')
+		{
+			localStorage.token = null;
+			UserActions.logout();
+		}
+		Webcore.init(Endpoints.base);
+	}
+
+	componentDidMount(){
+    UserStore.loadLocalStore();
+		if (localStorage.token === undefined) {
+			this.props.history.pushState(null, 'login');
+    }
+		if (this.props.location.pathname=='/')
+		{
+			this.props.history.pushState(null, 'login');
+		}
+
+    $("#menu-toggle").click(function (e) {
+      e.preventDefault();
+      $("#wrapper").toggleClass("toggled");
+    });
+	}
+	fetchPlugins(data) {
+		if (this.pluginsFetched)
+			return;
+		let self = this;
+		if (!data.success)
+			return;
+    this.setState(data);
+
+		Webcore.addPluginLoadListener(function(plugin) {
+      console.log("Plugin loaded to Dicoogle:", plugin);
+		});
+		Webcore.fetchPlugins('menu', (packages) => {
+			self.onMenuPlugin(packages);
+        Webcore.fetchModules(packages);
+		});
+
+
+    // pre-fetch modules of other plugin types
+		Webcore.fetchPlugins(['search', 'result-options', 'query', 'result'], Webcore.fetchModules)
+		this.pluginsFetched = true;
+  }
+
+	logout() {
+		const Dicoogle = dicoogleClient();
+		Dicoogle.request('POST', 'logout', {}, (error) => {
+      if (error) {
+        console.error(error);
+      }
+
+      this.setState({pluginMenuItems: []});
+      this.pluginsFetched = false;
+      UserActions.logout()
+
+			this.context.router.push('login');
+		});
+	}
+
+	render() {
+
+		return (
+		<div>
+			<div className="topbar">
+				<img className="btn_drawer" src="assets/drawer_menu.png" id="menu-toggle" />
+				<a>Dicoogle</a>
+        <div className="pull-right" bsStyle="padding:15px">
+
+          <span className="user-name usernameLogin" bsStyle="padding-right:10px">
+              {UserStore.getUsername()}
+          </span>
+
+          <span className="user-name buttonLogin">
+              <span onClick={this.logout.bind(this)} className="glyphicon glyphicon-log-out" style={{cursor: 'pointer'}} />
+          </span>
+
+        </div>
+      </div>
+
+			<div id="wrapper">
+				<div id="sidebar-wrapper">
+					<Sidebar pluginMenuItems={this.state.pluginMenuItems} onLogout={this.logout.bind(this)}/>
+				</div>
+				<div id="container" style={{display: 'block'}}>
+					{this.props.children}
+				</div>
+			</div>
+		</div>);
+	}
+}
+
+function NotFoundView() {
+	return (<div>
+    <h1>Not Found</h1>
+	</div>);
+}
+
+ReactDOM.render((
+  <Router history={hashHistory}>
+    <Route path="/" component={App}>
+      <IndexRoute component={LoadingView} />
+      <Route path="search" component={Search} />
+      <Route path="management" component={ManagementView} />
+      <Route path="results" component={SearchResultView} />
+      <Route path="indexer" component={IndexStatusView} />
+      <Route path="about" component={AboutView} />
+      <Route path="login" component={LoginView} />
+      <Route path="loading" component={LoadingView} />
+      <Route path="image/:uid" component={DirectImageView} />
+      <Route path="dump/:uid" component={DirectDumpView} />
+      <Route path="ext/:plugin" component={PluginView} />
+      <Route path="*" component={NotFoundView} />
+    </Route>
+  </Router>
+), document.getElementById('react-container'));
diff --git a/dicoogle/src/main/resources/webapp/js/components/about/aboutView.js b/dicoogle/src/main/resources/webapp/js/components/about/aboutView.js
new file mode 100644
index 0000000..61b1ba6
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/about/aboutView.js
@@ -0,0 +1,97 @@
+import React from 'react';
+
+import {VersionStore} from '../../stores/versionStore';
+import {VersionActions} from '../../actions/versionAction';
+import {Panel, Grid, Row, Col} from 'react-bootstrap';
+
+const AboutView = React.createClass({
+
+    getInitialState: function() {
+        return {version: ""};
+    },
+    componentWillMount: function() {
+    },
+    componentDidMount: function() {
+        // Subscribe to the store.
+        this.unsubscribe = VersionStore.listen(this.handleGetVersion);
+        VersionActions.get();
+    },
+    handleGetVersion: function(data) {
+        this.setState({version: data.data.version});
+    },
+    componentWillUnmount() {
+        this.unsubscribe();
+    },
+    render: function() {
+          let versionNumber = this.state.version;
+          var title = (
+              <h3>Dicoogle PACS, version: {versionNumber}</h3>
+          );
+          var licenses = (
+              <Grid className="">
+
+          <Row className="show-grid">
+          <Col className="gridAbout" xs={2} md={2}><b>dcm4che2</b><br/>License: GPL</Col>
+          <Col className="gridAbout" xs={2} md={2}><b>react.js+reflux</b><br/>License: BSD</Col>
+          <Col className="gridAbout" xs={2} md={2}><b>Jetty</b><br/>License: GPL</Col>
+          </Row>
+
+
+          </Grid>
+          );
+
+
+          var panelsInstance = (
+              <div className="about">
+          <Panel header={title} bsStyle="primary">
+          Dicoogle is an open source medical imaging repository with an extensible indexing system and distributed mechanisms.
+          Our solution can be used as a PACS archive, or as a client for reading your PACS archive file system, thus
+          allowing you to do PACS mining. Moreover, it can be easily extended with your own pluggable components.
+
+          At present, we have already indexed around 22 million DICOM images, and this number tends to increase.
+          There are several researchers working to evaluate and improve the quality of medical records, and Dicoogle has contributed to many of such case studies.
+
+          <br />
+
+          </Panel>
+
+          <Panel header="Main third party components" bsStyle="primary">
+
+          {licenses}
+
+           Note: Although these are not the only components used, these are considered the main ones.
+          </Panel>
+
+          <Panel header="Disclaimer" bsStyle="primary">
+          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.
+          </Panel>
+          <Panel header="Developers" bsStyle="primary">
+          As an open source software, Dicoogle can accept contributions from developers around the world.
+          Dicoogle OSS is led and supported by Bioinformatics UA and BMD Software. Please check <a target="_new" href="http://www.dicoogle.com">the Dicoogle website</a> or our <a target="_new" href="http://www.github.com/bioinformatics-ua/dicoogle">GitHub repository</a> for more information.
+
+          <div style={{display: 'inline-block', width: '100%'}}>
+            <a href="http://bioinformatics.ua.pt"><img src="assets/logos/logobio.png" style={{height: 40, margin: 5}} /></a>
+            <a href="http://bmd-software.com/"><img src="assets/logos/logo.png" style={{height: 40, padding: 5, margin: 5}} /></a>
+            <a href="http://www.ieeta.pt/"><img src="assets/logos/logo-ieeta.png" style={{height: 60, margin: 5}} /></a>
+            <a href="http://www.ua.pt/"><img src="assets/logos/logo-ua.png" style={{height: 60, margin: 5}} /></a>
+        </div>
+        <div style={{display: 'inline-block'}}>
+            <a><img src="assets/logos/logoFCT.png" style={{height: 30, margin: 5}} /></a>
+        </div>
+          </Panel>
+
+          </div>
+          );
+          return panelsInstance;
+
+        }
+      });
+
+export default AboutView;
diff --git a/dicoogle/src/main/resources/webapp/js/components/direct/directDumpView.js b/dicoogle/src/main/resources/webapp/js/components/direct/directDumpView.js
new file mode 100644
index 0000000..7b5b1cd
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/direct/directDumpView.js
@@ -0,0 +1,75 @@
+import React from 'react';
+import {DumpStore} from '../../stores/dumpStore';
+import {DumpActions} from '../../actions/dumpActions';
+import {getUrlVars} from '../../utils/url';
+import $ from 'jquery';
+
+const DirectDumpView = React.createClass({
+  propTypes: {
+    params: React.PropTypes.object.isRequired
+  },
+  getInitialState: function() {
+    return {data: [],
+    status: "loading",
+    current: 0};
+  },
+  componentDidMount: function() {
+    var uid = this.props.params.uid || getUrlVars()['SOPInstanceUID'];
+    DumpActions.get(uid);
+  },
+  componentWillMount: function() {
+    // Subscribe to the store.
+    DumpStore.listen(this._onChange);
+  },
+  componentDidUpdate: function(){
+    $('#dumptable').dataTable({paging: false, searching: false, info: false, responsive: false});
+  },
+
+  _onChange(data) {
+    if (this.isMounted())
+    {
+      this.setState({
+        data,
+        status: "stopped"
+      });
+    }
+  },
+
+	render() {
+		if(this.state.status === "loading") {
+      return (<div className="loader-inner ball-pulse"/>);
+    }
+    var obj = this.state.data.data.results.fields;
+    var rows = [];
+
+    var fields = [];
+    Object.keys(obj).forEach(function(key, i) {
+          rows.push(<p key={i}><b>{key}:</b> {obj[key]}</p>);
+          fields.push({att: key, field: obj[key]});
+        });
+
+    var fieldstable = fields.map((item) => {
+      return (
+        <tr>
+          <td> <p>{item.att}</p></td>
+          <td> <p>{item.field}</p></td>
+          </tr>
+      );
+    });
+
+		return (
+      <table id="dumptable" className="table-test table table-striped table-bordered responsive" cellSpacing="0" width="100%">
+        <thead>
+          <tr>
+            <th>Attribute</th>
+            <th>Field</th>
+          </tr>
+        </thead>
+        <tbody>
+          {fieldstable}
+        </tbody>
+      </table>);
+  }
+});
+
+export {DirectDumpView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/direct/directImageView.js b/dicoogle/src/main/resources/webapp/js/components/direct/directImageView.js
new file mode 100644
index 0000000..fb300bb
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/direct/directImageView.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import {getUrlVars} from '../../utils/url';
+import {Endpoints} from '../../constants/endpoints';
+
+export const DirectImageView = React.createClass({
+  propTypes: {
+    params: React.PropTypes.object.isRequired
+  },
+
+	getInitialState: function() {
+    return {error: false};
+  },
+
+	render() {
+    const instanceUid = this.props.params.uid || getUrlVars().SOPInstanceUID;
+    const url = Endpoints.base + "/dic2png?SOPInstanceUID=" + instanceUid;
+
+		return (this.state.error) ? (
+      <img src="assets/image-not-found.png" width="auto" height="300px" />
+      ) : (
+      <img src={url} width="100%" height="100%" onError={this.imageLoadError} />
+			);
+	},
+
+  imageLoadError() {
+    this.setState({error: true});
+  }
+});
diff --git a/dicoogle/src/main/resources/webapp/js/components/indexer/IndexStatusView.js b/dicoogle/src/main/resources/webapp/js/components/indexer/IndexStatusView.js
new file mode 100644
index 0000000..972e2bc
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/indexer/IndexStatusView.js
@@ -0,0 +1,106 @@
+import React from 'react';
+import {IndexStatusActions} from "../../actions/indexStatusAction";
+import {IndexStatusStore} from "../../stores/indexStatusStore";
+import TaskStatus from "./TaskStatus.jsx";
+
+var refreshIntervalId;
+const IndexStatusView = React.createClass({
+      getInitialState: function() {
+        return {data: {},
+        status: "loading"};
+      },
+      componentDidMount: function(){
+        IndexStatusActions.get();
+
+        //Start refresh interval
+        refreshIntervalId = setInterval(this.update, 3000);
+        //$("#consolediv").scrollTop($("#consolediv")[0].scrollHeight);
+       },
+       componentDidUpdate: function(){
+         console.log("indexstatus update");
+         //if(this.state.data.count !=0)
+         //{
+           //setInterval(IndexStatusActions.get(), 5000);
+         //}
+       },
+       componentWillUnmount: function(){
+         console.log("IndexStatusView unmounted");
+         //Stop refresh interval
+         clearInterval(refreshIntervalId);
+
+       },
+      update: function(){
+        IndexStatusActions.get();
+      },
+      componentWillMount: function() {
+         // Subscribe to the store.
+         console.log("subscribe listener");
+         IndexStatusStore.listen(this._onChange);
+       },
+      _onChange: function(data){
+        if (this.isMounted()){
+
+          this.setState({data: data.data, status: "done"});
+        }
+      },
+      render: function() {
+        if(this.state.status === "loading"){
+          return (<div className="loader-inner ball-pulse">
+            <div/><div/><div/>
+           </div>);
+        }
+
+        let items;
+        if (this.state.data.results.length === 0) {
+          items = (<div>No tasks</div>);
+        } else {
+          items = this.state.data.results.map(item => (
+            <TaskStatus key={item.taskUid} index={item.taskUid} item={item} onCloseStopClicked={this.onCloseStopClicked.bind(this, item.taskUid, item.complete)} />
+          ));
+        }
+        return (
+          <div className="">
+            <div className="panel panel-primary topMargin">
+              <div className="panel-heading">
+                <h3 className="panel-title">Start indexing</h3>
+              </div>
+              <div className="panel-body">
+                <div className="row">
+                  <div className="col-xs-6 col-sm-2">
+                    Index directory:
+                  </div>
+                  <div className="col-xs-6 col-sm-10">
+                    <input id="path" type="text" className="form-control" value={this.state.data.path} placeholder="/path/to/directory"/>
+                  </div>
+                </div>
+                <button className="btn btn_dicoogle" onClick={this.onStartClicked}>Start</button>
+              </div>
+            </div>
+            <div className="panel panel-primary topMargin">
+              <div className="panel-heading">
+                  <h3 className="panel-title">{this.state.data.count === 0 ? "No tasks currently running" :
+                    ("Indexing Status (" + this.state.data.count + " running)")}</h3>
+              </div>
+              <div className="panel-body">
+                  {items}
+              </div>
+            </div>
+          </div>
+        );
+      },
+      onStartClicked: function(){
+        IndexStatusActions.start(document.getElementById("path").value);
+      },
+      onCloseStopClicked: function(uid, type){
+        if(type){
+          IndexStatusActions.close(uid);
+        }
+        else{
+          IndexStatusActions.stop(uid);
+        }
+      }
+      });
+
+export {
+  IndexStatusView
+};
diff --git a/dicoogle/src/main/resources/webapp/js/components/indexer/TaskStatus.jsx b/dicoogle/src/main/resources/webapp/js/components/indexer/TaskStatus.jsx
new file mode 100644
index 0000000..5d9055f
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/indexer/TaskStatus.jsx
@@ -0,0 +1,84 @@
+import React, {PropTypes} from 'react';
+import {toHumanReadable} from '../../utils/time';
+
+class TaskStatus extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {};
+  }
+
+  static get propTypes() {
+    return {
+      item: PropTypes.shape({
+          taskUid: PropTypes.string.isRequired,
+          complete: PropTypes.bool,
+          canceled: PropTypes.bool,
+          taskProgress: PropTypes.number,
+          elapsedTime: PropTypes.number,
+          nIndexed: PropTypes.number,
+          nErrors: PropTypes.number
+        }).isRequired,
+      onCloseStopClicked: PropTypes.func.isRequired
+    };
+  }
+
+  render() {
+    const {item, onCloseStopClicked} = this.props;
+    const {complete, canceled} = item;
+    const unknownPercentage = (typeof item.taskProgress !== 'number' || item.taskProgress < 0);
+    const percentage = (complete || canceled || unknownPercentage) ? '100%'
+      : (Math.round(item.taskProgress * 100) + '%');
+
+    let barstate = "indexprogress progress-bar progress-bar-striped";
+    if (item.nErrors > 0 && item.nIndexed > 0) {
+      barstate += " progress-bar-warning";
+    } else if((item.nErrors > 0) && (item.nIndexed === 0)) {
+      barstate += " progress-bar-danger";
+    } else if (unknownPercentage && !complete) {
+      barstate += " progress-bar-info active";
+    } else {
+      barstate += " progress-bar-success";
+      if (!complete && !canceled) {
+        barstate += " active";
+      }
+    }
+    const barStyle = {
+      width: percentage
+    };
+    if (canceled) {
+      barStyle.backgroundColor = '#CCCCCC';
+    }
+
+  return (
+     <div key={item.taskUid} className="well well-sm">
+       <div className="row">
+      <div className="col-sm-10">
+        <div className="progress indexstatusprogress">
+          <div style={barStyle} className={barstate} role="progressbar" aria-valuemin="0" aria-valuemax="100">
+            {canceled ? 'canceled' : (!unknownPercentage && percentage)}
+          </div>
+        </div>
+      </div>
+      <div className="col-sm-2">
+        <button className="btn btn-danger" onClick={onCloseStopClicked}>
+          {(complete || canceled) ? "Close" : "Stop"}
+        </button>
+      </div>
+    </div>
+    <div>
+      <p><b>Uid: </b> {item.taskUid}</p>
+      <p><b>Name: </b> {item.taskName}</p>
+      <div style={{visibility: item.complete ? '' : 'hidden'}}>
+          {(typeof item.elapsedTime === 'number') && (
+            <p><b>Elapsed Time: </b> {toHumanReadable(item.elapsedTime)}</p>)}
+          {(typeof item.nIndexed === 'number') && (
+            <p><b>Indexed: </b> {item.nIndexed} </p>)}
+          {(typeof item.nErrors === 'number') && (
+            <p><b>Errors: </b> {item.nErrors} </p>)}
+        </div>
+      </div>
+    </div>);
+	}
+}
+
+export default TaskStatus;
diff --git a/dicoogle/src/main/resources/webapp/js/components/login/loadingView.js b/dicoogle/src/main/resources/webapp/js/components/login/loadingView.js
new file mode 100644
index 0000000..5604c26
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/login/loadingView.js
@@ -0,0 +1,60 @@
+import React, {PropTypes} from 'react';
+import {UserActions} from "../../actions/userActions";
+import {UserStore} from "../../stores/userStore";
+
+const LoadingView = React.createClass({
+  contextTypes: {
+    router: PropTypes.object.isRequired
+  },
+  getInitialState: function() {
+    return {data: {},
+    status: "loading"};
+  },
+  componentDidMount: function(){
+    //LoggerActions.get();
+    UserActions.isLoggedIn();
+  },
+  componentDidUpdate: function() {
+  },
+  componentWillMount: function() {
+    UserStore.listen(this._onChange);
+
+  },
+  _onChange: function(data){
+    const {router} = this.context;
+    console.log(data);
+    if(data.isLoggedIn && this.isMounted())
+    {
+      router.replace('/search');
+    }
+    else if(data.isLoggedIn === false){
+      router.replace('/login');
+    }
+  },
+  render: function() {
+    return (
+      <div id="loginwrapper" style={{position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', zIndex: 10000}}>
+        <div className="loginbody">
+          <div>
+            <img className="loginlogo" src="/assets/logo.png"></img>
+          </div>
+          <div className="loginloader">
+            <div className="loader-inner line-spin-fade-loader">
+              <div/>
+              <div/>
+              <div/>
+              <div/>
+              <div/>
+              <div/>
+              <div/>
+              <div/>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+});
+
+
+export default LoadingView;
diff --git a/dicoogle/src/main/resources/webapp/js/components/login/loginView.js b/dicoogle/src/main/resources/webapp/js/components/login/loginView.js
new file mode 100644
index 0000000..43cd1a4
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/login/loginView.js
@@ -0,0 +1,114 @@
+import React from 'react';
+import {UserActions} from "../../actions/userActions";
+import {UserStore} from "../../stores/userStore";
+import $ from 'jquery';
+
+const LoginView = React.createClass({
+  contextTypes: {
+    router: React.PropTypes.object.isRequired
+  },
+  getInitialState: function() {
+    return {data: {},
+    status: "loading",
+    failed: false};
+  },
+  componentDidMount: function(){
+    //LoggerActions.get();
+    this.enableEnterKey();
+  },
+  componentDidUpdate: function(){
+    this.enableEnterKey();
+  },
+  componentWillMount: function() {
+    UserStore.listen(this._onChange);
+
+  },
+  _onChange: function(data){
+    console.log(data);
+    const {router} = this.context;
+    if(data.failed === true)
+    {
+      this.setState({failed: true});
+      return;
+    }
+
+    if(data.isLoggedIn && this.isMounted())
+    {
+      router.replace('/search');
+      //React.unmountComponentAtNode(document.getElementById('login_container'));
+    }
+  },
+  enableEnterKey() {
+    var self = this;
+    var fh = function(e) {
+      if (e.keyCode === 13) {
+        self.onLoginClick();
+      }
+    };
+    $("#username").keypress(fh);
+    $("#password").keypress(fh);
+  },
+
+  render: function() {
+    return (
+      <div id="loginwrapper" style={{position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', zIndex: 10000}}>
+        <div className="loginbody">
+
+          <section className="container row-fluid loginbox logincontainer">
+
+            <img className="loginlogo" src="assets/logo.png" alt="Smiley face"/>
+
+            <div text-align="center" >
+
+              <h4 style={{textAlign: 'center'}}>
+                Improve your knowledge from your medical imaging repository.
+              </h4>
+
+            </div>
+
+            <div className="loginA">
+
+              <form className="form-horizontal">
+
+                <p className="loginTextA">Sign In</p>
+                <input ref="user" type="text" id="username" name="username" placeholder="Username" className="loginInputUsername form-control"/>
+                <input ref="pass" type="password" id="password" name="password" placeholder="Password" className="loginInputPassword form-control" />
+                  {this.state.failed ? (<p style={{color: 'red'}}> Login Failed. Please try again. </p>) : ''}
+                <button type="button" className="btn submit btn_dicoogle" onClick={this.onLoginClick}>Login</button>
+              </form>
+
+            </div>
+
+          </section>
+
+          <footer id="footer">
+            <div style={{width: '100%', textAlign: 'center'}} className="footercontainer">
+              <div style={{display: 'inline-block', width: '100%'}}>
+                <a href="http://bioinformatics.ua.pt"><img src="assets/logos/logobio.png" style={{height: 40, margin: 5}} /></a>
+                <a href="http://bmd-software.com/"><img src="assets/logos/logo.png" style={{height: 40, padding: 5, margin: 5}} /></a>
+                <a href="http://www.ieeta.pt/"><img src="assets/logos/logo-ieeta.png" style={{height: 60, margin: 5}} /></a>
+                <a href="http://www.ua.pt/"><img src="assets/logos/logo-ua.png" style={{height: 60, margin: 5}} /></a>
+              </div>
+              <div style={{display: 'inline-block'}}>
+                <a><img src="assets/logos/logoFCT.png" style={{height: 30, margin: 5}} /></a>
+              </div>
+
+            </div>
+          </footer>
+
+        </div>
+      </div>
+    );
+  },
+
+  onLoginClick: function(){
+    const user = document.getElementById("username").value;
+    const pass = document.getElementById("password").value;
+    //console.log("login clicked", user ,pass );
+    UserActions.login(user, pass);
+  }
+
+});
+
+
+export default LoginView;
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/indexerView.js b/dicoogle/src/main/resources/webapp/js/components/management/indexerView.js
new file mode 100644
index 0000000..1c64043
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/indexerView.js
@@ -0,0 +1,137 @@
+import React from 'react';
+import $ from 'jquery';
+
+import {IndexerStore} from '../../stores/indexerStore';
+import {IndexerActions} from '../../actions/indexerActions';
+import {saveIndexOptions} from '../../handlers/requestHandler';
+
+const ConfigurationEntry = React.createClass({
+  render() {
+    return <li className="list-group-item list-group-item-management">
+        <div className="row">
+            <div className="col-xs-6 col-sm-4">
+                {this.props.description}
+            </div>
+            <div className="col-xs-6 col-sm-8">
+                {this.props.children}
+            </div>
+        </div>
+    </li>
+  }
+});
+
+const IndexerView = React.createClass({
+
+      getInitialState: function() {
+        return {
+          data: {
+            path: "",
+            zip: false,
+            effort: 0,
+            thumbnail: false,
+            thumbnailSize: 0,
+            watcher: false
+          },
+          status: "loading",
+          currentWatch: false
+        };
+      },
+      componentDidMount: function() {
+        console.log("componentdidmount: get");
+
+        IndexerActions.get();
+       },
+      componentWillMount: function() {
+        // Subscribe to the store
+         console.log("subscribe listener");
+         IndexerStore.listen(this._onChange);
+      },
+      _onChange: function(data){
+        if (this.isMounted()){
+          console.log(data);
+          var nState = {data: data.data, status: "done"};
+          if (data.data.watcher) {
+            nState.currentWatch = data.data.watcher;
+          }
+          this.setState(nState);
+        }
+      },
+      onToggleWatcher() {
+        this.setState({currentWatch: !this.state.currentWatch});
+      },
+      render: function() {
+        if(this.state.status === "loading"){
+          return (<div className="loader-inner ball-pulse">
+            <div/><div/><div/>
+           </div>);
+        }
+        return (
+          <div className="tab-content">
+
+            <div className="panel panel-primary topMargin">
+                              <div className="panel-heading">
+                                  <h3 className="panel-title">Indexing Options</h3>
+                              </div>
+                              <div className="panel-body">
+
+                                  <ul className="list-group">
+                                      <ConfigurationEntry description="Enable Dicoogle Directory Watcher">
+                                        <input id="watcher" type="checkbox" aria-label="..." checked={this.state.currentWatch} onChange={this.onToggleWatcher} />
+                                      </ConfigurationEntry>
+                                      <ConfigurationEntry description="Dicoogle Watcher Directory">
+                                        <input id="mon_path" type="text" className="form-control" disabled={!this.state.currentWatch} defaultValue={this.state.data.path} placeholder="/path/to/directory"/>
+                                      </ConfigurationEntry>
+                                      <ConfigurationEntry description="Index Zip Files">
+                                        <input id="zip" type="checkbox" aria-label="..." defaultChecked={this.state.data.zip} onChange={this.onZipClicked}/>
+                                      </ConfigurationEntry>
+                                      <ConfigurationEntry description="Indexation Effort">
+                                        <input className="bar" type="range" id="effort_range" defaultValue={this.state.data.effort} onChange={this.onEffortChanged} />
+                                      </ConfigurationEntry>
+                                      <ConfigurationEntry description="Save Thumbnail">
+                                        <input id="save" type="checkbox" aria-label="..." defaultChecked={this.state.data.thumbnail} onChange={this.onSaveTClicked}/>
+                                      </ConfigurationEntry>
+                                      <ConfigurationEntry description="Thumbnail Size">
+                                        <input id="tsize" type="text" className="form-control" placeholder="Insert thumbnail size in pixels" defaultValue={this.state.data.thumbnailSize}/>
+                                      </ConfigurationEntry>
+                                  </ul>
+                                  <button className="btn btn_dicoogle" onClick={this.onSaveClicked}>
+                                    Save
+                                  </button>
+                                  <div className="toast">Saved</div>
+                                </div>
+                              </div>
+                          </div>
+        );
+      },
+
+      onWatcherClicked(e) {
+        //setWatcher(document.getElementById(id).checked);
+      },
+      onZipClicked(e) {
+        //setZip(document.getElementById(id).checked);
+      },
+      onSaveTClicked(e) {
+        //setSaveT(document.getElementById(id).checked);
+      },
+      onEffortChanged(e) {
+        //console.log(document.getElementById(id).value);
+      },
+      onSaveClicked() {
+        $('.toast').stop().fadeIn(400).delay(3000).fadeOut(400); //fade out after 3 seconds
+        console.log("onSaveClicked");
+        saveIndexOptions(
+          document.getElementById("mon_path").value,
+          document.getElementById("watcher").checked,
+          document.getElementById("zip").checked,
+          document.getElementById("save").checked,
+          document.getElementById("effort_range").value,
+          document.getElementById("tsize").value
+        );
+      }
+    });
+
+//<input className="bar" type="range" id="effort_range" defaultValue={this.props.value} onChange={this.props.onChange} />
+
+export {
+  IndexerView
+}
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/loggerView.js b/dicoogle/src/main/resources/webapp/js/components/management/loggerView.js
new file mode 100644
index 0000000..4d723be
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/loggerView.js
@@ -0,0 +1,56 @@
+import React from 'react';
+import $ from 'jquery';
+import {LoggerActions} from "../../actions/loggerActions";
+import {LoggerStore} from "../../stores/loggerStore";
+
+const LoggerView = React.createClass({
+  getInitialState: function() {
+    return {data: {},
+    status: "loading"};
+  },
+  componentDidMount: function(){
+
+    LoggerActions.get();
+    //$("#consolediv").scrollTop($("#consolediv")[0].scrollHeight);
+   },
+   componentDidUpdate: function(){
+     console.log("logger update");
+     $("#consolediv").scrollTop($("#consolediv")[0].scrollHeight);
+     //$("#consolediv").scrollTop(1000000);
+     //var objDiv = document.getElementById("consolediv");
+     //objDiv.scrollTop = 1000000;
+
+   },
+  componentWillMount: function() {
+     // Subscribe to the store.
+     console.log("subscribe listener");
+     LoggerStore.listen(this._onChange);
+   },
+  _onChange: function(data){
+    if (this.isMounted()){
+
+      this.setState({data: data.data, status: "done"});
+    }
+  },
+      render: function() {
+        if(this.state.status === "loading"){
+          return (<div className="loader-inner ball-pulse">
+            <div/><div/><div/>
+           </div>);
+        }
+        return (
+          <div className="panel panel-primary topMargin">
+                            <div className="panel-heading">
+                              Server Log
+                            </div>
+                            <div id="consolediv" className="panel-body scrolldiv">
+                              {this.state.data}
+                            </div>
+                          </div>
+        );
+        }
+      });
+
+export {
+  LoggerView
+}
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/managementView.js b/dicoogle/src/main/resources/webapp/js/components/management/managementView.js
new file mode 100644
index 0000000..e53467d
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/managementView.js
@@ -0,0 +1,46 @@
+import React from 'react';
+import {TransferOptionsView} from '../management/transferOptionsView';
+import {ServicesView} from '../management/servicesView';
+import {LoggerView} from '../management/loggerView';
+import {IndexerView} from '../management/indexerView';
+import {StorageView} from '../management/storageView';
+
+const ManagementView = React.createClass({
+    getInitialState: function() {
+      return {selectedtab: 0};
+    },
+    render: function() {
+      var views = [(<IndexerView/>),
+      (<TransferOptionsView/>),
+      (<ServicesView/>),
+      (<StorageView/>),
+      (<LoggerView/>)];
+      return (
+        <div className="container-fluid content">
+            <ul className="nav nav-pills">
+              <li className="active" role="presentation"><a href="#indexer" data-toggle="tab" onClick={this.onTabClicked.bind(this, 0)}>Index Options</a>
+              </li>
+                <li role="presentation"><a href="#transfer" data-toggle="tab" onClick={this.onTabClicked.bind(this, 1)}>Transfer Options</a>
+                </li>
+                <li role="presentation"><a href="#services" data-toggle="tab" onClick={this.onTabClicked.bind(this, 2)}>Services and Plugins</a>
+                </li>
+                <li role="presentation"><a href="#storage" data-toggle="tab" onClick={this.onTabClicked.bind(this, 3)}>Storage Servers</a>
+                </li>
+                <li role="presentation"><a href="#logs" data-toggle="tab" onClick={this.onTabClicked.bind(this, 4)}>Logs</a>
+                </li>
+            </ul>
+            <div id="my-tab-content" className="tab-content">
+              {views[this.state.selectedtab]}
+            </div>
+        </div>
+      );
+    },
+    onTabClicked: function(index){
+      console.log("tabSelected: ", index);
+      this.setState({selectedtab: index});
+    }
+});
+
+export {
+  ManagementView
+}
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/queryadvoptions.js b/dicoogle/src/main/resources/webapp/js/components/management/queryadvoptions.js
new file mode 100644
index 0000000..2e2594a
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/queryadvoptions.js
@@ -0,0 +1,141 @@
+import React from 'react';
+import {Button, Modal} from 'react-bootstrap';
+import ServiceAction from '../../actions/servicesAction';
+import ServicesStore from '../../stores/servicesStore';
+
+const QueryAdvancedOptionsModal = React.createClass({
+  getInitialState: function() {
+    return {
+      acceptTimeout: "...",
+      connectionTimeout: "...",
+      idleTimeout: "...",
+      maxAssociations: "...",
+      maxPduReceive: "...",
+      maxPduSend: "...",
+      responseTimeout: "...",
+      status: "loading"
+    };
+  },
+  componentWillMount: function() {
+    ServicesStore.listen(this._onChange);
+  },
+  componentDidMount: function() {
+  },
+  _onChange: function(data){
+    if (this.isMounted()) {
+      const querySettings = data.querySettings;
+      this.setState({
+        connectionTimeout: querySettings.connectionTimeout,
+        acceptTimeout: querySettings.acceptTimeout,
+        idleTimeout: querySettings.idleTimeout,
+        maxAssociations: querySettings.maxAssociations,
+        maxPduReceive: querySettings.maxPduReceive,
+        maxPduSend: querySettings.maxPduSend,
+        responseTimeout: querySettings.responseTimeout,
+        status: "done"
+      });
+    }
+   },
+  render: function() {
+    return (<Modal {...this.props} bsStyle='primary' title='Query Retrieve - Advanced Settings' animation>
+      <div className='modal-body'>
+        <div className="container-fluid">
+          <div className="row">
+            <div className="col-md-4">Response timeout:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_response_t"
+                     value={this.state.responseTimeout} onChange={this.handleResponseTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Connection timeout:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_connection_t"
+                     value={this.state.connectionTimeout} onChange={this.handleConnectionTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Idle timeout:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_idle_t"
+                     value={this.state.idleTimeout} onChange={this.handleIdleTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Accept timeout:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_accept_t"
+                     value={this.state.acceptTimeout} onChange={this.handleAcceptTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Max PDU Send:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_max_pdu_send"
+                     value={this.state.maxPduSend} onChange={this.handleMaxPduSendTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Max Associations:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_max_associations"
+                     value={this.state.maxAssociations} onChange={this.handleMaxAssociationsTimeoutChange}/>
+            </div>
+          </div>
+          <br></br>
+          <div className="row">
+            <div className="col-md-4">Max PDU Receive:</div>
+            <div className="col-md-8">
+              <input className="form-control" id="input_max_pdu_receive"
+                     value={this.state.maxPduReceive} onChange={this.handleMaxPduReceiveTimeoutChange}/>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div className='modal-footer'>
+        <Button onClick={this.onSave}>Save</Button>
+      </div>
+    </Modal>);
+  },
+  handleResponseTimeoutChange: function(event){
+    this.setState({responseTimeout: event.target.value});
+  },
+  handleConnectionTimeoutChange: function(event){
+    this.setState({connectionTimeout: event.target.value});
+  },
+  handleIdleTimeoutChange: function(event){
+    this.setState({idleTimeout: event.target.value});
+  },
+  handleAcceptTimeoutChange: function(event){
+    this.setState({acceptTimeout: event.target.value});
+  },
+  handleMaxPduSendTimeoutChange: function(event){
+    this.setState({maxPduSend: event.target.value});
+  },
+  handleMaxPduReceiveTimeoutChange: function(event){
+    this.setState({maxPduReceive: event.target.value});
+  },
+  handleMaxAssociationsTimeoutChange: function(event){
+    this.setState({maxAssociations: event.target.value});
+  },
+  onSave: function(){
+    console.log("onSave clicked");
+    ServiceAction.saveQuerySettings(
+      // TODO use state instead
+      document.getElementById("input_connection_t").value, // connection timeout
+      document.getElementById("input_accept_t").value, // accept timeout
+      document.getElementById("input_idle_t").value, // idle timeout
+      document.getElementById("input_max_associations").value, // max associations
+      document.getElementById("input_max_pdu_receive").value, // max PDU receive
+      document.getElementById("input_max_pdu_send").value, // max PDU send
+      document.getElementById("input_response_t").value); // response timeout
+      this.props.onHide();
+    }
+  });
+
+export default QueryAdvancedOptionsModal;
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/serviceForm.jsx b/dicoogle/src/main/resources/webapp/js/components/management/serviceForm.jsx
new file mode 100644
index 0000000..598af3d
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/serviceForm.jsx
@@ -0,0 +1,127 @@
+import React, {PropTypes} from 'react';
+import {FormGroup, FormControl} from 'react-bootstrap';
+
+export default class ServiceForm extends React.Component {
+
+  static get propTypes() {
+    return {
+      caption: PropTypes.string.isRequired,
+      running: PropTypes.bool.isRequired,
+      dirtyPort: PropTypes.bool.isRequired, // port has unsaved changes
+      onhold: PropTypes.bool,
+      port: PropTypes.oneOfType([
+        PropTypes.string.isRequired,
+        PropTypes.number.isRequired]).isRequired,
+      extraSettings: PropTypes.node,
+      onStartService: PropTypes.func.isRequired,
+      onStopService: PropTypes.func.isRequired,
+      onChangePort: PropTypes.func.isRequired,
+      onToggleAutostart: PropTypes.func.isRequired,
+      onSubmitPort: PropTypes.func.isRequired
+    };
+  }
+
+  constructor(props) {
+    super(props);
+    this.handlePortChange = this.handlePortChange.bind(this);
+    this.handlePortKeyPress = this.handlePortKeyPress.bind(this);
+    this.drawStatusCircle = this.drawStatusCircle.bind(this);
+    this.captureStatusCanvas = this.captureStatusCanvas.bind(this);
+  }
+
+  componentDidUpdate() {
+    this.drawStatusCircle();
+  }
+
+  isPortValid() {
+    return (/\d+/.test(this.props.port)
+          && +this.props.port > 0
+          && +this.props.port < 65536)
+  }
+
+  handlePortChange(e) {
+    this.props.onChangePort(e.target.value);
+  }
+
+  handlePortKeyPress(e) {
+    if (e.keyCode === 13) {
+      if (this.isPortValid()) {
+        this.props.onSubmitPort(this.props.port);
+      }
+    }
+  }
+
+  captureStatusCanvas(input) {
+    this._canvas = input;
+  }
+
+  render() {
+
+    return (
+      <div className="row">
+        <div className="col-xs-4">
+          <p>{this.props.caption}</p>
+          <canvas ref={this.captureStatusCanvas} width={30} height={30} />
+        </div>
+        <div className="col-xs-4">
+          <div className="data-table">
+            <div className="inline_block">Port</div>
+            <div className="inline_block" style={{marginLeft: '1em'}}>
+              <FormGroup validationState={this.isPortValid() ? 'success' : 'error'}>
+                <FormControl type="text" value={this.props.port}
+                            placeholder="Enter a valid port"
+                            disabled={this.props.disabledPort && "disabled"}
+                            onChange={this.handlePortChange}
+                            onKeyDown={this.handlePortKeyPress}/>
+                {this.props.dirtyPort && <FormControl.Feedback />}
+              </FormGroup>
+            </div>
+            <div className="checkbox">
+              <label>
+                <input type="checkbox" checked={this.props.autostart}
+                        onChange={this.props.onToggleAutostart}
+                        disabled={this.props.disabledAutostart && "disabled"} /> Auto Start
+              </label>
+            </div>
+          </div>
+        </div>
+        <div className="col-xs-4">
+          <div className="data-table">
+            <div className="inline_block">
+                { this.props.running ?
+                <button type="button" className="btn btn-danger" style={{marginTop: 20}}
+                        onClick={this.props.onStopService}>
+                  Stop
+                </button> :
+                <button type="button" className="btn btn-success" style={{marginTop: 20}}
+                        onClick={this.props.onStartService}>
+                  Start
+                </button>}
+            </div>
+            {this.props.extraSettings}
+            <div className="loader-inner ball-pulse"
+                style={{visibility: this.props.onhold ? 'visible' : 'hidden'}}>
+              <div/><div/><div/>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+  drawStatusCircle() {
+    const context = this._canvas.getContext('2d');
+    const centerX = this._canvas.width / 2;
+    const centerY = this._canvas.height / 2;
+    const radius = 13;
+
+    context.beginPath();
+    context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
+    context.fillStyle = this.props.running ? 'green' : 'red';
+    context.fill();
+    context.lineWidth = 1;
+    context.strokeStyle = '#003300';
+    context.stroke();
+  }
+
+}
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/servicesView.js b/dicoogle/src/main/resources/webapp/js/components/management/servicesView.js
new file mode 100644
index 0000000..24a5488
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/servicesView.js
@@ -0,0 +1,187 @@
+import React from 'react';
+import ServiceForm from './serviceForm.jsx';
+import ServiceAction from '../../actions/servicesAction';
+import ServicesStore from '../../stores/servicesStore';
+import QueryAdvancedOptionsModal from './queryadvoptions';
+import Webcore from 'dicoogle-webcore';
+import PluginView from '../plugin/pluginView';
+
+const ServicesView = React.createClass({
+
+    getInitialState () {
+        return {
+          storageRunning: false,
+          storagePort: '0',
+          storageDirtyPort: false,
+          storageAutostart: false,
+          queryRunning: false,
+          queryPort: '0',
+          queryDirtyPort: false,
+          queryAutostart: false,
+          status: "loading",
+          storageLoading: true,
+          queryLoading: true,
+          showingAdvanced: false,
+          plugins: []
+        };
+    },
+
+    componentWillMount () {
+      ServicesStore.listen(this._onChange);
+      Webcore.fetchPlugins('settings', (packages) => {
+        Webcore.fetchModules(packages);
+        this.setState({plugins: packages.map(pkg => ({
+          name: pkg.name,
+          caption: pkg.dicoogle.caption || pkg.name
+        }))});
+      });
+    },
+
+    componentDidMount () {
+      ServiceAction.getStorage();
+      ServiceAction.getQuery();
+    },
+
+    _onChange (data) {
+      console.log(data);
+      if(this.isMounted()) {
+        this.setState({
+        storageRunning: data.storageRunning,
+        storagePort: data.storagePort,
+        storageAutostart: data.storageAutostart,
+        queryRunning: data.queryRunning,
+        queryPort: data.queryPort,
+        queryAutostart: data.queryAutostart,
+        status: "done",
+        storageLoading: false,
+        queryLoading: false
+        });
+
+        console.log("Service data update: ", data);
+      }
+    },
+
+    render () {
+      if(this.state.status === "loading"){
+        return (<div className="loader-inner ball-pulse">
+          <div/><div/><div/>
+          </div>);
+      }
+      const pluginElements = this.state.plugins.map(p =>(
+        <li key={'plugin/' + p.name} className="list-group-item list-group-item-management">
+          <div>
+            <div className="row">
+              <div className="col-xs-4">
+                <p>{p.caption}</p>
+              </div>
+              <div className="col-xs-8">
+                <PluginView plugin={p.name} slotId="settings" />
+              </div>
+            </div>
+          </div>
+        </li>
+      ));
+
+      const extraQRSettings = (
+        <button type="button" className="btn btn-default" style={{marginTop: 20, float: 'right'}} onClick={this.showAdvanced}>
+          <span className="glyphicon glyphicon-cog" />
+        </button>);
+
+      return (
+      <div className="panel panel-primary topMargin">
+        <div className="panel-heading">
+          <h3 className="panel-title">Services</h3>
+        </div>
+        <div className="panel-body">
+          <ul className="list-group">
+            <li key="storage" className="list-group-item list-group-item-management">
+              <ServiceForm caption="Storage" running={this.state.storageRunning} autostart={this.state.storageAutostart}
+                           dirtyPort={this.state.storageDirtyPort} port={this.state.storagePort}
+                           onhold={this.state.storageLoading} extraSettings={null}
+                           onStartService={this.startStorage} onStopService={this.stopStorage}
+                           onChangePort={this.handleStoragePortChange}
+                           onToggleAutostart={this.handleToggleStorageAutostart}
+                           onSubmitPort={this.handleSubmitStoragePort} />
+            </li>
+            <li key="query" className="list-group-item list-group-item-management">
+              <ServiceForm caption="Query Retrieve" running={this.state.queryRunning} autostart={this.state.queryAutostart}
+                           dirtyPort={this.state.queryDirtyPort} port={this.state.queryPort}
+                           onhold={this.state.queryLoading} extraSettings={extraQRSettings}
+                           onStartService={this.startQuery} onStopService={this.stopQuery}
+                           onChangePort={this.handleQueryPortChange}
+                           onToggleAutostart={this.handleToggleQueryAutostart}
+                           onSubmitPort={this.handleSubmitQueryPort} />
+            </li>
+            {pluginElements}
+          </ul>
+          <QueryAdvancedOptionsModal show={this.state.showingAdvanced} onHide={this.onHideAdvanced} />
+        </div>
+      </div>
+      );
+    },
+    showAdvanced() {
+      this.setState({showingAdvanced: true});
+      ServiceAction.getQuerySettings();
+    },
+    onHideAdvanced() {
+      this.setState({showingAdvanced: false});
+    },
+    handleQueryPortChange(portNumber) {
+      this.setState({
+        queryPort: portNumber,
+        queryDirtyPort: true
+      });
+    },
+    handleStoragePortChange (portNumber) {
+      this.setState({
+        storagePort: portNumber,
+        storageDirtyPort: true
+      });
+    },
+    handleStorageRunning(enable) {
+      if (enable) {
+        this.startStorage();
+      } else {
+        this.stopStorage();
+      }
+    },
+    handleQueryRunning(enable) {
+      if (enable) {
+        this.startQuery();
+      } else {
+        this.stopQuery();
+      }
+    },
+    startStorage () {
+      ServiceAction.setStorage(true);
+    },
+    stopStorage () {
+      ServiceAction.setStorage(false);
+    },
+    handleToggleStorageAutostart () {
+      const newAutostart = !this.state.storageAutostart;
+      this.setState({storageAutostart: newAutostart, storageLoading: true});
+      ServiceAction.setStorageAutostart(newAutostart);
+    },
+    handleToggleQueryAutostart () {
+      const newAutostart = !this.state.queryAutostart;
+      this.setState({queryAutostart: newAutostart, queryLoading: true});
+      ServiceAction.setQueryAutostart(newAutostart);
+    },
+    handleSubmitStoragePort(port) {
+      this.setState({storageDirtyPort: false, storageLoading: true});
+      ServiceAction.setStoragePort(port);
+    },
+    handleSubmitQueryPort(port) {
+      this.setState({queryDirtyPort: false, queryLoading: true});
+      ServiceAction.setQueryPort(port);
+    },
+    startQuery () {
+      ServiceAction.setQuery(true);
+    },
+    stopQuery () {
+      ServiceAction.setQuery(false);
+    }
+});
+
+export {ServicesView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/storageView.js b/dicoogle/src/main/resources/webapp/js/components/management/storageView.js
new file mode 100644
index 0000000..401caeb
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/storageView.js
@@ -0,0 +1,184 @@
+import React from 'react';
+
+import {StorageActions} from '../../actions/storageActions';
+import {StorageStore} from '../../stores/storageStore';
+import {Button, Modal, FormGroup, FormControl, ControlLabel, Checkbox, HelpBlock} from 'react-bootstrap';
+
+const AddStorageModal = React.createClass({
+    getInitialState() {
+      return {
+        aetitle: '',
+        ip: '',
+        port: '',
+        public: false
+      };
+    },
+
+  render: function() {
+    const valAETitle = this.validateAETitle();
+    return(<Modal {...this.props} bsStyle='primary' animation>
+      <Modal.Header>
+        <Modal.Title>Add Storage Server</Modal.Title>
+      </Modal.Header>
+      <Modal.Body>
+        <div>
+          <FormGroup validationState={valAETitle.code}>
+            <ControlLabel>AE Title</ControlLabel>
+            <FormControl style={{width: '100%'}} type="text"
+                    placeholder="AE Title" onChange={this.handleChangeAETitle}
+                    value={this.state.aetitle} />
+            <HelpBlock>{valAETitle.help}</HelpBlock>
+          </FormGroup>
+          <FormGroup validationState={this.validateIPAddress()}>
+            <ControlLabel>IP Address</ControlLabel>
+            <FormControl style={{width: '100%'}} type="text"
+                  placeholder="IP Address" onChange={this.handleChangeIPAddress} />
+          </FormGroup>
+          <FormGroup validationState={this.validatePort()}>
+            <ControlLabel>Port</ControlLabel>
+            <FormControl style={{width: '100%'}} type="text"
+                  placeholder="Port" onChange={this.handleChangePort}
+                  onKeyDown={this.handleFieldKeyDown} />
+          </FormGroup>
+          <FormGroup>
+            <ControlLabel>Description</ControlLabel>
+            <FormControl style={{width: '100%'}} type="text"
+                  onChange={this.handleChangeDescription} onKeyDown={this.handleFieldKeyDown} />
+          </FormGroup>
+          <FormGroup>
+            <Checkbox inline value={this.state.public} onChange={this.handleChangePublic}>
+              Public
+            </Checkbox>
+          </FormGroup>
+        </div>
+      </Modal.Body>
+      <Modal.Footer>
+        <Button bsClass="btn btn_dicoogle" disabled={!this.validateAll()} onClick={this.handleAdd}>Add</Button>
+        <Button onClick={this.props.onHide}>Cancel</Button>
+      </Modal.Footer>
+    </Modal>);
+  },
+  
+  handleFieldKeyDown(e) {
+    if (e.keyCode === 13) {
+      if (this.validateAll()) {
+        this.handleAdd();
+      }
+    }
+  },
+
+  handleChangeAETitle(e) {
+    this.setState({aetitle: e.target.value.toUpperCase()});
+  },
+  handleChangeIPAddress(e) {
+    this.setState({ip: e.target.value});
+  },
+  handleChangePort(e) {
+    this.setState({port: e.target.value});
+  },
+  handleChangeDescription(e) {
+    this.setState({description: e.target.value});
+  },
+  handleChangePublic(e) {
+    this.setState({public: !this.state.public});
+  },
+
+  validateAETitle(input) {
+    input = (input || this.state.aetitle).trim();
+    if (input === '') return {code: undefined, help: ''};
+    if (input.length <= 16) return {code: 'success', help: ''};
+    // AETitle length should be 16, but there are some implementations not respecting it.
+    if (input.length <= 64) return {code: 'warning', help: 'This AE title is not DICOM compliant. Dicoogle will accept it anyway.'};
+    return {code: 'error', help: 'Invalid AE title. Please shorten the device\'s AE title length.'};
+  },
+  validateIPAddress(input) {
+    input = (input || this.state.ip).trim();
+    return input.length > 0 ? 'success' : undefined;
+  },
+  validatePort(input) {
+    input = (input || this.state.port).trim();
+    if (input === '') return undefined;
+    const v = +input;
+    return (v > 0 && v < 65536) ? 'success' : 'error';
+  },
+  validateAll() {
+    const aet = this.validateAETitle(this.state.aetitle).code;
+    return (aet === 'warning' || aet === 'success')
+        && this.validateIPAddress(this.state.ip) === 'success'
+        && this.validatePort(this.state.port) === 'success';
+  },
+
+  handleAdd () {
+    const {aetitle, ip, port, description} = this.state;
+    StorageActions.add(aetitle, ip, port, description, this.state.public);
+    this.props.onHide();
+  }
+});
+
+const StorageView = React.createClass({
+    getInitialState: function() {
+      return {
+        data: [],
+        showAdd: false,
+        status: "loading",
+        selectedIndex: null
+      };
+    },
+    componentDidMount() {
+      StorageActions.get();
+    },
+    componentWillMount() {
+      this.unsubscribe = StorageStore.listen(this._onChange);
+    },
+    componentWillUnmount() {
+      this.unsubscribe();
+    },
+    _onChange: function(data){
+      this.setState({data: data.data});
+    },
+
+    render: function() {
+      const moves = this.state.data.map((item, index) => (
+            <option key={index} value={index} onClick={this.handleSelect}>
+              {item.aetitle + " @ " + item.ip + ":" + item.port}
+              {item.description && (" - " + item.description)}
+              {item.public && ' (public)'}
+            </option>));
+
+      return (
+
+        <div className="panel panel-primary topMargin">
+          <div className="panel-heading">
+            Storage Servers
+          </div>
+          <div className="panel-body">
+            <select defaultValue={0} className="form-control" size={6} style={{width: '100%'}}>
+              {moves}
+            </select>
+            <div style={{textAlign: 'left', marginTop: '8px'}}>
+              <button className="btn btn_dicoogle" onClick={this.onAdd}>Add New</button>
+              <button className="btn btn_dicoogle" disabled={typeof this.state.selectedIndex !== 'number'}
+                      onClick={this.onRemove}>Remove</button>
+            </div>
+          </div>
+          <AddStorageModal show={this.state.showAdd} onHide={this.onHideAdd} />
+        </div>
+      );
+    },
+    handleSelect(e) {
+      this.setState({selectedIndex: +e.target.value});
+    },
+    onAdd() {
+      this.setState({showAdd: true});
+    },
+    onHideAdd() {
+      this.setState({showAdd: false});
+    },
+    onRemove() {
+      const index = this.state.selectedIndex;
+      StorageActions.remove(index);
+    }
+
+});
+
+export {StorageView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/management/transferOptionsView.js b/dicoogle/src/main/resources/webapp/js/components/management/transferOptionsView.js
new file mode 100644
index 0000000..61c495e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/management/transferOptionsView.js
@@ -0,0 +1,138 @@
+import React from 'react';
+
+import {TransferStore} from '../../stores/transferStore';
+import {TransferActions} from '../../actions/transferActions';
+import {Endpoints} from '../../constants/endpoints';
+import $ from 'jquery';
+import {Button} from 'react-bootstrap';
+
+const TransferOptionsView = React.createClass({
+
+      getInitialState () {
+        this.selectAllOn = true;
+        return {
+          data: [],
+          status: "loading",
+          selectedIndex: 0
+        };
+      },
+      componentDidMount() {
+        console.log("componentdidmount: get");
+
+        TransferActions.get();
+      },
+      componentWillMount() {
+         // Subscribe to the store.
+         console.log("subscribe listener");
+         TransferStore.listen(this._onChange);
+      },
+      _onChange (data){
+        if (this.isMounted()){
+          console.log(data);
+          this.setState({data: data, status: "done"});
+        }
+      },
+      render () {
+        if(this.state.status === "loading")
+        {
+          return (<div className="loader-inner ball-pulse">
+            <div/><div/><div/>
+           </div>);
+        }
+
+        var array = this.state.data;
+        console.log("array", array);
+        var options = (
+            array.data[this.state.selectedIndex].options.map((item, index) => {
+                return(
+                  (<div key={index} className="data-table-row">
+                      <label className="checkbox" title="1.2.840.10008.1.2.1.99">
+                          <input type="checkbox" id={item.name} name="GlobalTransferStorageTransferStorage0" checked={item.value}
+                            onChange={this.handleChange.bind(this, item.name, index)}/>{item.name}</label>
+                  </div>
+                  )
+                );
+            })
+          );
+
+        var sopclasses = (
+          array.data.map((item, index) => {
+
+            return (<option key={index}>{item.sop_name} -- {item.uid}</option>);
+          })
+        );
+
+        return (
+          <div>
+          <div className="tab-pane" id="transfer">
+                <div className="panel panel-primary topMargin">
+                    <div className="panel-heading">
+                        <h3 className="panel-title">SOP Class Global Transfer Storage Options</h3>
+                    </div>
+                    <div className="panel-body">
+                        <ul className="list-group">
+
+                            <select id="sop_select"className="form-control" onChange={this.onSopSelected}>
+                              {sopclasses}
+                            </select>
+                            <li className="list-group-item list-group-item-management">
+                                <div className="row">
+                                    <div className="col-xs-6 col-sm-4">
+                                        Global Transfer Storage
+                                    </div>
+                                    <div className="col-xs-6 col-sm-8">
+                                        <div id="GlobalTransferStorage" className="data-table">
+                                          {options}
+                                        </div>
+                                    </div>
+                                </div>
+                            </li>
+                        </ul>
+                        <div>
+                            <Button bsStyle="primary" onClick={this.handleSelectAll}>{this.selectAllOn ? 'Select all' : 'Unselect all'}</Button>
+
+                        </div>
+                    </div>
+                </div>
+            </div>
+          </div>
+        );
+
+      },
+
+      handleSelectAll()
+      {
+          if (this.selectAllOn)
+              TransferActions.selectAll();
+          else
+              TransferActions.unSelectAll();
+
+          this.selectAllOn = !this.selectAllOn;
+
+      },
+      handleChange(id, index) {
+        TransferActions.set(this.state.selectedIndex, index, document.getElementById(id).checked);
+        this.request(id, document.getElementById(id).checked);
+      },
+
+      onSopSelected() {
+        var selectedId = document.getElementById("sop_select").selectedIndex;
+
+        this.setState({selectedIndex: selectedId});
+      },
+
+      request(id, value) {
+        var uid = this.state.data.data[document.getElementById("sop_select").selectedIndex].uid;
+        console.log("Selected uid:", uid);
+        $.post(Endpoints.base + "/management/settings/transfer", {
+          uid: uid,
+          option: id,
+          value: value
+        }, (data, status) => {
+          //Response
+          console.log("Data: " + data + "\nStatus: " + status);
+        });
+      }
+});
+
+export { TransferOptionsView };
diff --git a/dicoogle/src/main/resources/webapp/js/components/mixins/userMixin.js b/dicoogle/src/main/resources/webapp/js/components/mixins/userMixin.js
new file mode 100644
index 0000000..9b0f016
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/mixins/userMixin.js
@@ -0,0 +1,20 @@
+import {Router} from 'react-router';
+import {UserStore} from '../../stores/userStore';
+
+const UserMixin = {
+  mixins: [Router.Navigation],
+  componentWillMount: function() {
+    if(UserStore.getLogginState() === false)
+    {
+      console.log("usermixin", "NOOOO");
+      this.transitionTo('loading');
+    }
+    else{
+      console.log("usermixin", "yesss");
+      document.getElementById('container').style.display = 'block';
+    }
+  }
+
+};
+
+export {UserMixin}
diff --git a/dicoogle/src/main/resources/webapp/js/components/plugin/pluginForm.jsx b/dicoogle/src/main/resources/webapp/js/components/plugin/pluginForm.jsx
new file mode 100644
index 0000000..77b30db
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/plugin/pluginForm.jsx
@@ -0,0 +1,58 @@
+import React, {PropTypes} from 'react';
+import {ResultsSelected} from '../../stores/resultSelected';
+import dicoogleClient from 'dicoogle-client';
+const Dicoogle = dicoogleClient();
+
+export default class PluginFormModal extends React.Component {
+
+  static get propTypes() {
+    return {
+      slotId: PropTypes.string.isRequired,
+      plugin: PropTypes.shape({
+        name: PropTypes.string.isRequired,
+        caption: PropTypes.string
+      }),
+      data: React.PropTypes.object,
+      onHide: PropTypes.func.isRequired
+    };
+  }
+
+  constructor(props) {
+    super(props);
+    this.handleMounted = this.handleMounted.bind(this);
+    this.handleHideSignal = this.handleHideSignal.bind(this);
+  }
+
+  onConfirm() {
+    this.props.onHide();
+  }
+
+  handleMounted(component) {
+    if (component) {
+      const node = component;
+      node.addEventListener('hide', this.handleHideSignal);
+      Dicoogle.emitSlotSignal(node, 'result-selection-ready', ResultsSelected.get());
+    }
+  }
+
+  handleHideSignal({target}) {
+      console.log('Plugin requested to hide');
+      target.removeEventListener('hide', this.handleHideSignal);
+      this.props.onHide();
+  }
+
+  render() {
+    const {plugin} = this.props;
+    return (plugin &&
+      <div>
+
+          <dicoogle-slot {...this.props.data} ref={this.handleMounted} data-slot-id={this.props.slotId} data-plugin-name={plugin.name}>
+            {plugin.name && <div className="loader-inner ball-pulse">
+              <div/><div/><div/>
+            </div>}
+          </dicoogle-slot>
+
+      </div>
+    );
+  }
+}
diff --git a/dicoogle/src/main/resources/webapp/js/components/plugin/pluginView.jsx b/dicoogle/src/main/resources/webapp/js/components/plugin/pluginView.jsx
new file mode 100644
index 0000000..3cb7072
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/plugin/pluginView.jsx
@@ -0,0 +1,76 @@
+import React from 'react';
+
+class PluginView extends React.Component {
+
+  static get propTypes() {
+    return {
+      // React router fills this with a plugin name
+      params: React.PropTypes.object,
+      // the plugin name
+      plugin: React.PropTypes.string,
+      slotId: React.PropTypes.string,
+      data: React.PropTypes.object
+    };
+  }
+
+  static get defaultProps() {
+    return {
+      slotId: 'menu'
+    };
+  }
+
+  constructor(props) {
+    super(props);
+    this.state = {
+      elements: {}
+    };
+    this.handleMounted = this.handleMounted.bind(this);
+    this.handleLoaded = this.handleLoaded.bind(this);
+  }
+
+  handleMounted(component) {
+    if (component) {
+      const node = component;
+      node.addEventListener('plugin-load', e => {
+        //console.log('[plugin-load]', e);
+        if (e && e.detail) {
+          this.handleLoaded(e.detail);
+        }
+      });
+    }
+  }
+
+  handleLoaded(element) {
+    if (React.isValidElement(element)) {
+      const elements = {};
+      elements[this.getPluginName()] = element;
+      for (const name in this.state.elements) {
+        elements[name] = this.state.elements[name];
+      }
+      this.setState({
+        elements
+      });
+    }
+  }
+
+  getPluginName() {
+    return this.props.plugin || (this.props.params && this.props.params.plugin);
+  }
+
+  render() {
+    const plugin = this.getPluginName();
+    return (
+      <div className={this.props.className} style={this.props.style}>
+        {this.state.elements[plugin] ?
+        <div>{this.state.elements[plugin]}</div> :
+        <dicoogle-slot {...this.props.data} ref={this.handleMounted} data-slot-id={this.props.slotId} data-plugin-name={plugin}>
+          {plugin && <div className="loader-inner ball-pulse">
+            <div/><div/><div/>
+          </div>}
+        </dicoogle-slot>}
+      </div>
+    );
+  }
+}
+
+export default PluginView;
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/advancedSearch.js b/dicoogle/src/main/resources/webapp/js/components/search/advancedSearch.js
new file mode 100644
index 0000000..c9ae445
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/advancedSearch.js
@@ -0,0 +1,218 @@
+
+import $ from 'jquery';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import {SearchStore} from '../../stores/searchStore';
+import {ActionCreators} from '../../actions/searchActions';
+import {SearchResult} from './searchResult';
+
+// TODO this component needs to be refactored:
+// - it should not perform React renders
+// - it should delegate the actual search to the parent component
+
+const AdvancedSearch = React.createClass({
+    getInitialState: function (){
+        return { label: 'login' };
+    },
+    componentDidMount: function() {
+      $("#datepicker").datepicker();
+    },
+
+    render: function() {
+        var managementInstance = (
+            <div>
+                 <div id="filter-group">
+                    <div className="row space_up">
+                        <div className="col-xs-12 col-sm-8">
+                            <div className="globalmargin">
+                                <div className="subject_text">Patient Name</div>
+                                <input id="patient_name" type="text" className="form-control" placeholder="(All Patients)"></input>
+                            </div>
+                            <div className="globalmargin">
+                                <div className="subject_text">Patient ID</div>
+                                <input id="patient_id"type="text" className="form-control" placeholder="(All Patient IDs)"></input>
+                            </div>
+                            <div className="globalmargin">
+                                <div className="subject_text">Patient Gender</div>
+                                <div className="inline_block">
+                                    All
+                                    <input id="gender_all" type="radio" name='genderRadio'></input>Male
+                                    <input id="gender_male" type="radio" name='genderRadio'></input>Female
+                                    <input id="gender_female" type="radio" name='genderRadio'></input>
+
+                                </div>
+                            </div>
+                            <div className="globalmargin">
+                                <div className="subject_text">Instituition Name</div>
+                                <input id="instituition" type="text" className="form-control" placeholder="(All Institutions)"></input>
+                            </div>
+                            <div className="globalmargin">
+                                <div className="subject_text">Physician</div>
+                                <input id="physician" type="text" className="form-control" placeholder="(All Physicians)"></input>
+                            </div>
+                            <div className="globalmargin">
+                                <div className="subject_text">Operator Name</div>
+                                <input id="OperatorName" type="text" className="form-control" placeholder="(All Operators)"></input>
+                            </div>
+
+
+                        </div>
+                        <div className="col-xs-12 col-sm-4">
+                            <div className="subject_text space_up">Modality</div>
+                            <div className="modalities">
+                                <label htmlFor="modCR">CR</label>
+                                <input id="modCR" type="checkbox" name="CR" />
+
+                                <label htmlFor="modMG">MG</label>
+                                <input id="modMG" type="checkbox" name="MG" />
+
+                                <label htmlFor="modPT">PT</label>
+                                <input id="modPT" type="checkbox" name="PT" />
+
+                                <label htmlFor="modXA">XA</label>
+                                <input id="modXA" type="checkbox" name="XA" />
+
+                                <label htmlFor="modES">ES</label>
+                                <input id="modES" type="checkbox" name="ES" />
+
+
+                                <label htmlFor="modCT">CT</label>
+                                <input id="modCT" type="checkbox" name="CT" />
+
+                                <label htmlFor="modMR">MR</label>
+                                <input id="modMR" type="checkbox" name="MR" />
+
+                                <label htmlFor="modRF">RF</label>
+                                <input id="modRF" type="checkbox" name="RF" />
+
+                                <label htmlFor="modUS">US</label>
+                                <input id="modUS" type="checkbox" name="US" />
+
+                                <label htmlFor="modDX">DX</label>
+                                <input id="modDX" type="checkbox" name="DX" />
+
+                                <label htmlFor="modNM">NM</label>
+                                <input id="modNM" type="checkbox" name="NM" />
+
+                                <label htmlFor="modSC">SC</label>
+                                <input id="modSC" type="checkbox" name="SC" />
+
+                                <label htmlFor="modOT">OT</label>
+                                <input id="modOT" type="checkbox" name="OT" />
+
+                            </div>
+                            <div className="subject_text space_up">Date</div>
+                            <input type="text" id="datepicker"></input>
+
+                        </div>
+
+                    </div>
+                    <button type="button" className="btn btn_dicoogle centerDivH" onClick={this.onSearchClicked}>Search</button>
+                </div>
+            </div>
+            );
+        return managementInstance;
+    },
+    componentWillMount: function() {
+    // Subscribe to the store.
+        SearchStore.listen(this._onChange);
+
+    },
+
+    _onChange: function(data){
+        console.log(data);
+     //    if (this.isMounted())
+     // this.setState({label:data});
+   },
+   onSearchClicked: function(){
+     console.log("SEARCH CLICKED");
+       //NAME
+       var patientName = document.getElementById("patient_name").value;
+       var query = "PatientName: " + this.checkEmpty(patientName); //TODO FINISH
+
+       //GENDER
+       var gender;
+       if (document.getElementById('gender_male').checked) {
+          gender = " AND PatientSex:M";
+       }
+       else if(document.getElementById('gender_female').checked){
+         gender = " AND PatientSex:F";
+       }
+       else
+       {
+         gender = "";
+       }
+       query = query + gender;
+       //ID
+       var patientId = document.getElementById("patient_id").value;
+       if(this.checkEmpty(patientId) !== "*")
+       query = query + " AND PatientID: " + this.checkEmpty(patientId);
+       //Instituition
+       var instituition = document.getElementById("instituition").value;
+       if(this.checkEmpty(instituition) !== "*")
+       query = query + " AND InstitutionName: " + this.checkEmpty(instituition);
+       //Pshysician
+       var physician = document.getElementById("physician").value;
+       if(this.checkEmpty(physician) !== "*")
+       query = query + " AND PerformingPhysicianName: " + this.checkEmpty(physician);
+       //OperatorName
+       var OperatorName = document.getElementById("OperatorName").value;
+       if(this.checkEmpty(OperatorName) !== "*")
+       query = query + " AND OperatorName: " + this.checkEmpty(OperatorName);
+       ///////
+
+       var mods = document.querySelector(".modalities");
+       var mods_checked = Array.prototype.slice.call(mods.querySelectorAll('input'));
+
+       var modalities = "";
+       mods_checked.forEach(function(element){
+         //console.log(element.checked);
+         if(element.checked)
+         {
+           modalities = modalities + " " + element.name;
+         }
+       })
+
+       if(modalities !== "")
+       {
+         modalities = " AND Modality: (" + modalities + ")";
+         query = query + modalities;
+       }
+
+       //DATE
+       if(document.getElementById("datepicker").value !== "")
+       {
+         var date = $('#datepicker').datepicker('getDate').getFullYear() + this.fix2($('#datepicker').datepicker('getDate').getMonth()) + this.fix2($('#datepicker').datepicker('getDate').getDate());
+
+         query = query + " AND StudyDate:[" + date + " TO " + date + "]";
+       }
+
+       var providerEl = document.getElementById("providersList");
+       var selectedId = providerEl.selectedIndex;
+       var provider = "";
+       if(selectedId === 0){
+         provider = "all"
+       }
+       else {
+          provider = providerEl.options[selectedId].text;
+       }
+
+       ///////
+       var params = {text: query, keyword: true, other: true, provider};
+
+       ReactDOM.render(<SearchResult items={params}/>, document.getElementById("container"));
+  },
+   checkEmpty: function(text){
+     if(text.length === 0 )
+      return "*";
+     else
+      return text;
+   },
+   fix2: function(n) {
+        return (n < 10) ? '0' + n : n;
+    }
+});
+
+export {AdvancedSearch};
+
+window.action = ActionCreators;
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/exportView.js b/dicoogle/src/main/resources/webapp/js/components/search/exportView.js
new file mode 100644
index 0000000..1be8af0
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/exportView.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import {Button, Modal} from 'react-bootstrap';
+
+import {ExportActions} from '../../actions/exportActions';
+import {ExportStore} from '../../stores/exportStore';
+
+const ExportView = React.createClass({
+	getInitialState: function() {
+      return {data: [],
+      status: "loading",
+      current: 0};
+    },
+    componentDidMount: function() {
+    },
+	componentDidUpdate: function() {
+	},
+	componentWillMount: function() {
+		// Subscribe to the store.
+		console.log("subscribe listener");
+		ExportStore.listen(this._onChange);
+	},
+	_onChange: function(data){
+		if (this.isMounted()){
+
+			this.setState({data: data.data, status: "done"});
+		}
+	},
+
+	render: function(){
+    return (
+      <Modal {...this.props} bsStyle='primary' title='Export to CSV' animation>
+        <div className='modal-body'>
+            <textarea id="textFields" placeholder="Paste export fields here (one per line) ..." rows="10" className="exportlist form-control"></textarea>
+        </div>
+        <div id="hacked-modal-footer" className='modal-footer'>
+          <Button onClick={this.onExportClicked}>Export</Button>
+        </div>
+      </Modal>);
+	},
+
+  onExportClicked: function(){
+    //console.log("onExportCLicked", document.getElementById("textFields").value);
+		var fields = document.getElementById("textFields").value.split("\n");
+		console.log(fields);
+
+		var query = this.props.query;
+		ExportActions.exportCSV(query, fields);
+  }
+});
+
+export {ExportView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/result/confirmModal.js b/dicoogle/src/main/resources/webapp/js/components/search/result/confirmModal.js
new file mode 100644
index 0000000..af0865c
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/result/confirmModal.js
@@ -0,0 +1,29 @@
+
+import React from 'react';
+import {Modal} from 'react-bootstrap';
+
+const ConfirmModal = React.createClass({
+    onConfirm: function() {
+        this.props.onConfirm();
+        this.props.onHide();
+    },
+    render: function() {
+        var body_message = this.props.message || "The following files will be unindexed. This operation might be irreversible.";
+        return (
+          <Modal {...this.props} animation={false}>
+            <Modal.Header>
+              <Modal.Title>Are you sure?</Modal.Title>
+            </Modal.Header>
+            <div className="modal-body">
+              {body_message}
+            </div>
+            <div className="modal-footer">
+                <button className="btn btn_dicoogle" onClick={this.props.onHide}> Cancel</button>
+                <button className="btn btn-warning" onClick={this.onConfirm}> Confirm</button>
+            </div>
+          </Modal>
+        );
+  }
+});
+
+export default ConfirmModal;
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/result/imageView.js b/dicoogle/src/main/resources/webapp/js/components/search/result/imageView.js
new file mode 100644
index 0000000..6f16ef3
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/result/imageView.js
@@ -0,0 +1,372 @@
+import React from 'react';
+import {Button, Modal} from 'react-bootstrap';
+import {SearchStore} from '../../../stores/searchStore';
+import {ActionCreators} from '../../../actions/searchActions';
+import ConfirmModal from './confirmModal';
+import {Endpoints} from '../../../constants/endpoints';
+import {DumpStore} from '../../../stores/dumpStore';
+import ImageLoader from 'react-imageloader';
+import PluginView from '../../plugin/pluginView';
+import {DumpActions} from '../../../actions/dumpActions';
+import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
+import {Input} from 'react-bootstrap';
+import ResultSelectActions from '../../../actions/resultSelectAction';
+import {UserStore} from '../../../stores/userStore';
+
+const ImageView = React.createClass({
+    getInitialState: function() {
+      // We need this because refs are not updated in BootstrapTable.
+      this.refsClone = {};
+      return {data: [],
+        image: null,
+        dump: null,
+        status: "loading",
+        unindexSelected: null,
+        removeSelected: null
+      };
+    },
+
+    componentWillMount: function() {
+      // Subscribe to the store.
+      SearchStore.listen(this._onChange);
+      ResultSelectActions.clear();
+    },
+
+
+  /**
+   * 2015-09-11:
+   * This method returns a React Component that only has the text and couple of
+   * events (such as click). Today, react-bootstrap-table does not support selectRows
+   * without appear radio ou checkbox.
+   */
+
+  formatGlobal: function(text, item) {
+    return (<div className="" style={{"cursor": "pointer"}}>
+        {text}
+    </div>);
+  },
+  formatFileName: function(cell, item){
+    return this.formatGlobal(item.filename, item);
+  },
+  formatSOPInstanceUID: function(cell, item){
+    return this.formatGlobal(item.sopInstanceUID, item);
+  },
+  _preloader: function (){
+     return <img src="spinner.gif" />;
+
+  },
+  formatThumbUrl: function(cell, item){
+    let self = this;
+    let uid = item.sopInstanceUID;
+    let thumbUrl = Endpoints.base + "/dic2png?thumbnail=true&SOPInstanceUID=" + uid;
+
+    return (<div onClick={self.showImage.bind(self, uid)}><ImageLoader
+                src={thumbUrl}
+                style={{"width": "64px", "cursor": "pointer"}}
+                wrapper={React.DOM.div}>
+              <img src="assets/image-not-found.png" width="64px" />
+          </ImageLoader></div>)
+  },
+  formatViewOptions: function(cell, item){
+    let self = this;
+    let uid = item.sopInstanceUID;
+    return (<div>
+            <button title="Dump Image" type="button" onClick={self.showDump.bind(self, uid)} className="btn btn_dicoogle btn-xs fa fa-table"> </button>
+            <button title="Show Image" type="button" onClick={self.showImage.bind(self, uid)} className="btn btn_dicoogle btn-xs fa fa-eye"> </button>
+          </div>);
+  },
+
+  formatOptions: function(cell, item){
+      let self = this;
+      let isAdmin = UserStore.isAdmin();
+      let unindex = null;
+      let removeFiles = null;
+      if (this.props.enableAdvancedSearch) {
+          if (isAdmin) {
+              unindex = (
+                  <button title="Unindex (does not remove file physically)"
+                          onClick={self.showUnindex.bind(null, item)}
+                          className="btn btn_dicoogle btn-xs fa fa-eraser">
+                  </button>);
+
+              removeFiles = (<button title="Removes the file physically"
+                                     onClick={self.showRemove.bind(null, item)}
+                                     className="btn btn_dicoogle btn-xs fa fa-trash-o">
+              </button>);
+          }
+          return (<div>
+                  {unindex}
+                  {removeFiles}
+
+
+                  {/* plugin-based result options*/}
+                  <PluginView style={{display: 'inline-block'}} slotId="result-options" data={{
+                  'data-result-type': 'image',
+                  'data-result-uri': item.uri,
+                  'data-result-uid': item.sopInstanceUID
+                 }}/>
+              </div>
+
+          );
+      }
+      return (<div></div>);
+  },
+
+    handleSelect(item){
+        let {sopInstanceUID} = item;
+        // ResultSelectActions.select(item);
+        let value = this.refsClone[sopInstanceUID].getChecked();
+        if (value)
+            ResultSelectActions.select(item, sopInstanceUID);
+        else
+            ResultSelectActions.unSelect(item, sopInstanceUID);
+
+
+    },
+  handleRefs: function (id, input){
+      this.refsClone[id] = input;
+  },
+  formatSelect: function (cell, item){
+    let {sopInstanceUID} = item;
+    let classNameForIt = "advancedOptions " + sopInstanceUID;
+    return (<div className={classNameForIt}>
+              <Input type="checkbox" label=""
+                    onChange={this.handleSelect.bind(this, item)}
+                    ref={this.handleRefs.bind(this, sopInstanceUID)}/>
+            </div>
+    );
+  },
+
+  sizePerPageListChange(sizePerPage){
+
+  },
+
+  onPageChange(page, sizePerPage) {
+
+  },
+
+  onRowSelect: function(row) {
+    this.props.onItemClick(row);
+  },
+
+	render: function() {
+		let self = this;
+		var resultArray = this.props.serie.images;
+
+    var selectRowProp = {
+      clickToSelect: true,
+      mode: "none",
+      bgColor: "rgb(163, 210, 216)",
+      onSelect: this.onRowSelect
+    };
+     // TODO trigger this action elsewhere
+    ResultSelectActions.level("image");
+    return (
+        <div>
+            <BootstrapTable data={resultArray} selectRow={selectRowProp} condensed
+                  pagination striped hover width="100%">
+              <TableHeaderColumn dataAlign="left" dataField="filename"
+                isKey dataFormat={this.formatFileName} dataSort>
+                  File Name
+              </TableHeaderColumn>
+              <TableHeaderColumn dataAlign="left" dataField="sopInstanceUID"
+                dataFormat={this.formatSOPInstanceUID} dataSort>
+                  SOPInstanceUID
+              </TableHeaderColumn>
+
+              <TableHeaderColumn dataAlign="center"
+                dataFormat={this.formatViewOptions} dataField="sopInstanceUID"
+                dataSort>View
+              </TableHeaderColumn>
+              <TableHeaderColumn dataAlign="center" dataField="sopInstanceUID"
+                dataFormat={this.formatThumbUrl}
+                dataSort>
+                Thumbnail
+              </TableHeaderColumn>
+
+              <TableHeaderColumn hidden={!this.props.enableAdvancedSearch}
+                dataAlign="center" dataField="sopInstanceUID"
+                dataSort={false} dataFormat={this.formatOptions}>
+                Options
+              </TableHeaderColumn>
+              <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="sopInstanceUID" dataSort dataFormat={this.formatSelect}>
+              #S
+              </TableHeaderColumn>
+            </BootstrapTable>
+
+          <ConfirmModal show={self.state.unindexSelected !== null}
+                        onHide={self.hideUnindex}
+                        onConfirm={self.onUnindexConfirm.bind(self, self.state.unindexSelected)}/>
+          <ConfirmModal show={self.state.removeSelected !== null}
+                        message="The following files will be unindexed and then deleted from their storage."
+                        onHide={self.hideRemove}
+                        onConfirm={self.onRemoveConfirm.bind(self, self.state.removeSelected)}/>
+          <PopOverView uid={this.state.dump} onHide={this.onHideDump} />
+          <PopOverImageViewer uid={this.state.image} onHide={this.onHideImage}/>
+        </div>
+      );
+	},
+  onHideDump() {
+    if (this.isMounted())
+      this.setState({dump: null});
+  },
+  onHideImage() {
+    if (this.isMounted())
+      this.setState({image: null});
+  },
+  showDump(uid) {
+    if (this.isMounted())
+      this.setState({dump: uid, image: null, unindexSelected: null});
+      DumpActions.get(uid);
+  },
+  showImage(uid) {
+    if (this.isMounted())
+      this.setState({dump: null, image: uid, unindexSelected: null});
+  },
+  hideUnindex() {
+    if (this.isMounted())
+      this.setState({
+        unindexSelected: null
+      });
+  },
+  showUnindex(item) {
+    if (this.isMounted())
+      this.setState({
+        unindexSelected: item, dump: null, image: null
+      });
+  },
+  hideRemove() {
+    if (this.isMounted())
+      this.setState({
+        removeSelected: null
+      });
+  },
+  showRemove(item) {
+      if (this.isMounted())
+    this.setState({
+      removeSelected: item, dump: null, image: null
+    });
+  },
+  onUnindexConfirm (item){
+    console.log(item)
+    var uris = [];
+    uris.push(item.uri);
+    let p = this.props.provider;
+    ActionCreators.unindex(uris, p);
+  },
+  onRemoveConfirm: function(item){
+    var uris = [];
+    uris.push(item.uri);
+    ActionCreators.remove(uris);
+  },
+    _onChange: function(data){
+      if (this.isMounted())
+      {
+        this.setState({data: data.data,
+          status: "stopped",
+          success: data.success
+        });
+      }
+    }
+});
+
+var PopOverView = React.createClass({
+	getInitialState: function() {
+    return {data: null,
+      status: "loading",
+      current: 0
+    };
+  },
+  componentWillMount: function() {
+    // Subscribe to the store.
+    DumpStore.listen(this._onChange);
+  },
+
+  _onChange: function(data){
+    if (this.isMounted()) {
+      this.setState({data, status: "stopped"});
+    }
+  },
+
+  onHide () {
+    this.setState({data: null});
+    this.props.onHide();
+  },
+
+	render: function() {
+		if(this.state.data === null) {
+			return (
+				<Modal {...this.props} show={this.props.uid !== null} bsStyle='primary' title='Image Dump' animation>
+          <div className="loader-inner ball-pulse">
+            <div/>
+            <div/>
+            <div/>
+          </div>
+        </Modal>);
+    }
+
+    var obj = this.state.data.data.results.fields;
+    var rows = [];
+
+    var fields = [];
+    Object.keys(obj).forEach(function(key, i) {
+          rows.push(<p key={i}><b>{key}:</b> {obj[key]}</p>);
+          fields.push({att: key, field: obj[key]});
+       });
+
+    var selectRowProp = {
+      clickToSelect: true,
+      mode: "none",
+      bgColor: "rgb(163, 210, 216)",
+      onSelect: this.onRowSelect
+    };
+		return (
+			<Modal onHide={this.props.onHide} show={this.props.uid !== null} bsClass='modal' bsStyle='primary' dialogClassName='table-dump'animation>
+          <Modal.Header>
+            <Modal.Title>Dump DICOM metadata</Modal.Title>
+          </Modal.Header>
+            <div className='modal-body'>
+              <BootstrapTable search columnFilter data={fields} selectRow={selectRowProp} condensed pagination striped hover
+                              className="table-test table table-striped table-bordered responsive" cellspacing="0" width="100%">
+              <TableHeaderColumn dataAlign="right"
+                dataField="att" width="20%" isKey dataSort>Attribute</TableHeaderColumn>
+              <TableHeaderColumn dataAlign="left"
+                dataField="field"
+                width="40%" isKey={false} dataSort>Field</TableHeaderColumn>
+
+              </BootstrapTable>
+            </div>
+            <div className='modal-footer'>
+              <Button onClick={this.props.onHide}>Close</Button>
+            </div>
+			</Modal>
+			);
+	}
+});
+
+var PopOverImageViewer = React.createClass({
+
+	render() {
+    let url = (this.props.uid !== null) && Endpoints.base + "/dic2png?SOPInstanceUID=" + this.props.uid;
+		return (
+			<Modal onHide={this.props.onHide} show={this.props.uid !== null} bsStyle='primary' animation>
+          <Modal.Header>
+            <Modal.Title>View Image</Modal.Title>
+          </Modal.Header>
+          <div className='modal-body'>
+            <ImageLoader
+                src={url}
+                style={{"width": "100%"}}
+                wrapper={React.DOM.div}>
+              <img src="assets/image-not-found.png" width="100%" />
+          </ImageLoader>
+          </div>
+          <div className='modal-footer'>
+            <Button onClick={this.props.onHide}>Close</Button>
+          </div>
+			</Modal>
+    );
+	}
+});
+
+export {ImageView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/result/patientView.js b/dicoogle/src/main/resources/webapp/js/components/search/result/patientView.js
new file mode 100644
index 0000000..03b2aaa
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/result/patientView.js
@@ -0,0 +1,224 @@
+import React from 'react';
+import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
+import {ActionCreators} from '../../../actions/searchActions';
+import {SearchStore} from '../../../stores/searchStore';
+import ConfirmModal from './confirmModal';
+import PluginView from '../../plugin/pluginView.jsx';
+import {Input} from 'react-bootstrap';
+import ResultSelectActions from '../../../actions/resultSelectAction';
+import {UserStore} from '../../../stores/userStore';
+
+
+  /**
+   * 2015-09-11.
+   * TODO: Read the Note.
+   * Note:
+   * Dear Dicoogle Hacker, I know that you are upset with me
+   * because we did not use mixin here, studies, series and image.
+   * I understand your frustration, but I strongly believe, that I near future
+   * we will be able to improve it as it desires.
+   * Best Regards.
+   *
+   * ^^^
+   * WAT
+   */
+const PatientView = React.createClass({
+  getInitialState() {
+
+    // We need this because refs are not updated in BootstrapTable.
+    this.refsClone = {};
+
+    return {
+      unindexSelected: null,
+      removeSelected: null,
+      resultsSelected: []
+    }
+  },
+
+  componentWillMount: function() {
+    // Subscribe to the store.
+    SearchStore.listen(this._onChange);
+    ResultSelectActions.clear();
+  },
+
+  /**
+   * 2015-09-11:
+   * This method returns a React Component that only has the text and couple of
+   * events (such as click). Today, react-bootstrap-table does not support selectRows
+   * without appear radio ou checkbox.
+   */
+
+  formatGlobal: function(text, item){
+    return (<div onClick={this.onPatientClick.bind(this, item)} className="" style={{"cursor": "pointer"}}>  {text}
+    </div>)
+  },
+  formatID: function(cell, item){
+    return this.formatGlobal(item.id, item);
+  },
+  formatGender: function(cell, item){
+    return this.formatGlobal(item.gender, item);
+  },
+  formatNumberOfStudies: function(cell, item){
+    return this.formatGlobal(item.nStudies, item);
+  },
+  formatName: function(cell, item){
+    return this.formatGlobal(item.name, item);
+  },
+
+  formatOptions: function(cell, item){
+
+          let isAdmin = UserStore.isAdmin();
+          let unindex = null;
+          let removeFiles = null;
+          if (this.props.enableAdvancedSearch)
+          {
+              if (isAdmin) {
+                  unindex = (
+                      <button title="Unindex (does not remove file physically)" onClick={this.showUnindex.bind(null, item)}
+                              className="btn btn_dicoogle btn-xs fa fa-eraser"/>);
+
+                  removeFiles = (<button title="Removes the file physically" onClick={this.showRemove.bind(null, item)}
+                                         className="btn btn_dicoogle btn-xs fa fa-trash-o"/>);
+              }
+          }
+          if (this.props.enableAdvancedSearch)
+              return (<div>
+                    {unindex}
+                    {removeFiles}
+                {/* plugin-based result options */}
+                <PluginView style={{display: 'inline-block'}} slotId="result-options" data={{
+                  'data-result-type': 'patient',
+                  'data-result-patient': item.name,
+                  'data-result-patientid': item.id
+                }} />
+            </div>);
+          return (<div></div>);
+
+  },
+  handleSelect(item){
+      let {id} = item;
+     // ResultSelectActions.select(item);
+      let value = this.refsClone[id].getChecked();
+      if (value)
+        ResultSelectActions.select(item, id);
+      else
+        ResultSelectActions.unSelect(item, id);
+
+
+  },
+  handleRefs: function (id, input){
+      this.refsClone[id] = input;
+  },
+  formatSelect: function (cell, item){
+    let {id} = item;
+    let classNameForIt = "advancedOptions " + id;
+    return (<div className={classNameForIt}>
+              <Input type="checkbox" label=""
+                    onChange={this.handleSelect.bind(this, item)}
+                    ref={this.handleRefs.bind(this, id)}/>
+            </div>
+    );
+  },
+  onRowSelect: function(row, isSelected){
+    this.props.onItemClick(row);
+  },
+  onPatientClick: function(item){
+    this.props.onItemClick(item);
+  },
+  sizePerPageListChange(sizePerPage){
+
+  },
+
+  onPageChange(page, sizePerPage) {
+
+  },
+	render: function() {
+    this.options = {
+      sortName: 'id',
+      sortOrder: 'desc',
+      sizePerPageList: [ 5, 10, 20, 50, 100, 200 ],
+      sizePerPage: 50,
+      onPageChange: this.onPageChange
+    };
+
+    let resultArray = this.props.items.results;
+    let selectRowProp = {
+      clickToSelect: true,
+      mode: "none",
+      bgColor: "rgb(163, 210, 216)",
+      onSelect: this.onRowSelect
+    };
+
+    // TODO trigger this action elsewhere
+    ResultSelectActions.level("patient");
+    return (
+        <div>
+          <BootstrapTable options={this.options} data={resultArray} selectRow={selectRowProp} condensed pagination striped hover width="100" >
+            <TableHeaderColumn dataAlign="right" dataField="id" isKey dataFormat={this.formatID} dataSort>ID</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="left" dataField="name" dataFormat={this.formatName} isKey={false} dataSort>Name</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="center" dataField="gender" dataFormat={this.formatGender} dataSort>Gender</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="center" dataField="nStudies" dataFormat={this.formatNumberOfStudies} dataSort>#Studies</TableHeaderColumn>
+            <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="Opts" dataSort={false} dataFormat={this.formatOptions}>Options</TableHeaderColumn>
+            <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="Select" dataSort dataFormat={this.formatSelect}>#S</TableHeaderColumn>
+          </BootstrapTable>
+
+          <ConfirmModal show={this.state.unindexSelected !== null}
+                      onHide={this.hideUnindex}
+                      onConfirm={this.onUnindexConfirm.bind(this, this.state.unindexSelected)}/>
+          <ConfirmModal show={this.state.removeSelected !== null}
+                      message="The following files will be unindexed and then deleted from their storage."
+                      onHide={this.hideRemove}
+                      onConfirm={this.onRemoveConfirm.bind(this, this.state.removeSelected)}/>
+        </div>);
+	},
+  extractURISFromData: function(item){
+    var uris = [];
+    for(let s in item.studies)
+      for(let ss in item.studies[s].series)
+        for(let i in item.studies[s].series[ss].images)
+          uris.push(item.studies[s].series[ss].images[i].uri);
+    return uris;
+  },
+  onUnindexConfirm: function(item){
+    let uris = this.extractURISFromData(item);
+    let p = this.props.provider;
+
+    ActionCreators.unindex(uris, p);
+  },
+  onRemoveConfirm: function(item){
+    let uris = this.extractURISFromData(item);
+    ActionCreators.remove(uris);
+  },
+  hideUnindex () {
+    this.setState({
+      unindexSelected: null
+    });
+  },
+  showUnindex (index) {
+    this.setState({
+        unindexSelected: index
+    });
+  },
+  hideRemove () {
+    if (this.isMounted())
+        this.setState({
+            removeSelected: null
+        });
+  },
+  showRemove (index) {
+      this.setState({
+          removeSelected: index,
+          unindexSelected: null
+      });
+  },
+  _onChange: function(data){
+    if (this.isMounted())
+    {
+      this.setState({data: data.data,
+      status: "stopped",
+      success: data.success});
+    }
+  }
+});
+
+export {PatientView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/result/serieView.js b/dicoogle/src/main/resources/webapp/js/components/search/result/serieView.js
new file mode 100644
index 0000000..37147f0
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/result/serieView.js
@@ -0,0 +1,224 @@
+import React from 'react';
+import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
+import {SearchStore} from '../../../stores/searchStore';
+import {ActionCreators} from '../../../actions/searchActions';
+import ConfirmModal from './confirmModal';
+import PluginView from '../../plugin/pluginView.jsx';
+import {Input} from 'react-bootstrap';
+import ResultSelectActions from '../../../actions/resultSelectAction';
+import {UserStore} from '../../../stores/userStore';
+
+
+const SeriesView = React.createClass({
+  getInitialState: function() {
+    // We need this because refs are not updated in BootstrapTable.
+    this.refsClone = {};
+    return {
+      data: [],
+      status: "loading",
+      unindexSelected: null,
+      removeSelected: null
+    };
+  },
+
+  componentWillMount: function() {
+    // Subscribe to the store.
+    SearchStore.listen(this._onChange);
+    ResultSelectActions.clear();
+  },
+
+  /**
+   * 2015-09-11:
+   * This method returns a React Component that only has the text and couple of
+   * events (such as click). Today, react-bootstrap-table does not support selectRows
+   * without appear radio ou checkbox.
+   *
+   */
+
+  formatGlobal: function(text, item){
+    let self = this;
+    return (<div onClick={self.onSeriesClick.bind(this, item)} className="" style={{"cursor": "pointer"}}>  {text}
+    </div>)
+  },
+
+  _wrapResult: function(result){
+    if (result === undefined)
+      result = "";
+    return result;
+  },
+  formatNumber: function(cell, item){
+    return this._wrapResult(this.formatGlobal(item.serieNumber, item));
+
+  },
+  formatModality: function(cell, item){
+    return this._wrapResult(this.formatGlobal(item.serieModality, item));
+  },
+  formatDescription: function(cell, item){
+    return this._wrapResult(this.formatGlobal(item.serieDescription, item));
+  },
+  formaImages: function(cell, item){
+    return this._wrapResult(this.formatGlobal(item.images.length, item));
+  },
+
+  formatOptions: function(cell, item){
+      let self = this;
+      let isAdmin = UserStore.isAdmin();
+      let unindex = null;
+      let removeFiles = null;
+
+
+
+    if (this.props.enableAdvancedSearch)
+      {
+        if (isAdmin) {
+          unindex = (
+              <button title="Unindex (does not remove file physically)" onClick={self.showUnindex.bind(null, item)} className="btn btn_dicoogle btn-xs fa fa-eraser"> </button>);
+          removeFiles = (<button title="Removes the file physically" onClick={self.showRemove.bind(null, item)} className="btn btn_dicoogle btn-xs fa fa-trash-o"> </button>);
+        }
+        return (<div>
+
+              {unindex}
+              {removeFiles}
+
+              {/* plugin-based result options */}
+              <PluginView style={{display: 'inline-block'}} slotId="result-options" data={{
+          'data-result-type': 'series',
+          'data-result-uid': item.serieInstanceUID
+         }} />
+            </div>
+        );
+
+      }
+
+      return (<div></div>);
+  },
+
+  handleSelect(item){
+
+    let {serieInstanceUID} = item;
+    // ResultSelectActions.select(item);
+    let value = this.refsClone[serieInstanceUID].getChecked();
+    if (value)
+      ResultSelectActions.select(item, serieInstanceUID);
+    else
+      ResultSelectActions.unSelect(item, serieInstanceUID);
+
+  },
+  handleRefs: function (id, input){
+    this.refsClone[id] = input;
+  },
+  formatSelect: function (cell, item){
+    let {serieInstanceUID} = item;
+    let classNameForIt = "advancedOptions " + serieInstanceUID;
+    return (<div className={classNameForIt}>
+              <Input type="checkbox" label=""
+                    onChange={this.handleSelect.bind(this, item)}
+                    ref={this.handleRefs.bind(this, serieInstanceUID)}/>
+            </div>
+    );
+  },
+  sizePerPageListChange(sizePerPage){
+
+  },
+
+  onPageChange(page, sizePerPage) {
+
+  },
+
+  onRowSelect: function(row){
+    this.props.onItemClick(row);
+  },
+  onSeriesClick: function(item){
+		this.props.onItemClick(item);
+	},
+	render: function() {
+		const self = this;
+
+    var resultArray = this.props.study.series;
+
+    var selectRowProp = {
+      clickToSelect: true,
+      mode: "none",
+      bgColor: "rgb(163, 210, 216)",
+      onSelect: this.onRowSelect
+    };
+
+
+    // TODO trigger this action elsewhere
+    ResultSelectActions.level("series");
+
+
+    return (
+			<div>
+        <BootstrapTable data={resultArray} selectRow={selectRowProp} condensed pagination striped hover width="100%">
+          <TableHeaderColumn dataAlign="right" dataField="serieInstanceUID" isKey dataFormat={this.formatNumber} dataSort>Number</TableHeaderColumn>
+          <TableHeaderColumn dataAlign="left" dataField="serieModality" dataFormat={this.formatModality} isKey={false} dataSort>Modality</TableHeaderColumn>
+          <TableHeaderColumn dataAlign="center" dataField="serieDescription" dataFormat={this.formatDescription} dataSort>Description</TableHeaderColumn>
+          <TableHeaderColumn dataAlign="center" dataField="serieInstanceUID" dataFormat={this.formaImages} dataSort>#Images</TableHeaderColumn>
+          <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="serieInstanceUID" isKey={false} dataSort={false} dataFormat={this.formatOptions}>Options</TableHeaderColumn>
+          <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="serieInstanceUID" dataSort dataFormat={this.formatSelect}>#S</TableHeaderColumn>
+          </BootstrapTable>
+        <ConfirmModal show={self.state.unindexSelected !== null}
+                      onHide={self.hideUnindex}
+                      onConfirm={self.onUnindexConfirm.bind(self, self.state.unindexSelected)}/>
+        <ConfirmModal show={self.state.removeSelected !== null}
+                      message="The following files will be unindexed and then deleted from their storage."
+                      onHide={self.hideRemove}
+                      onConfirm={self.onRemoveConfirm.bind(self, self.state.removeSelected)}/>
+			</div>
+		);
+	},
+  hideUnindex () {
+    if (this.isMounted())
+      this.setState({
+        unindexSelected: null
+      });
+  },
+  showUnindex (item) {
+    if (this.isMounted())
+      this.setState({
+        unindexSelected: item
+      });
+  },
+  hideRemove () {
+    if (this.isMounted())
+      this.setState({
+        removeSelected: null
+      });
+  },
+  showRemove (item) {
+    if (this.isMounted())
+      this.setState({
+        removeSelected: item
+      });
+  },
+	extractURISFromData: function(item){
+		let uris = [];
+		for(let i in item.images)
+			uris.push(item.images[i].uri);
+		return uris;
+	},
+	onUnindexConfirm: function(item){
+		console.log(item)
+		let uris = this.extractURISFromData(item);
+		let p = this.props.provider;
+		ActionCreators.unindex(uris, p);
+	},
+	onRemoveConfirm: function(item){
+		let uris = this.extractURISFromData(item);
+		ActionCreators.remove(uris);
+	},
+
+  _onChange: function(data){
+
+    if (this.isMounted())
+    {
+      this.setState({data: data.data,
+      status: "stopped",
+      success: data.success,
+      enableAdvancedSearch: data.data.advancedOptions});
+    }
+  }
+});
+
+export {SeriesView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/result/studyView.js b/dicoogle/src/main/resources/webapp/js/components/search/result/studyView.js
new file mode 100644
index 0000000..cc7937b
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/result/studyView.js
@@ -0,0 +1,215 @@
+import React from 'react';
+import {SearchStore} from '../../../stores/searchStore';
+import {BootstrapTable, TableHeaderColumn} from 'react-bootstrap-table';
+
+import {ActionCreators} from '../../../actions/searchActions';
+import ConfirmModal from './confirmModal';
+import PluginView from '../../plugin/pluginView.jsx';
+import {Input} from 'react-bootstrap';
+import ResultSelectActions from '../../../actions/resultSelectAction';
+
+import {UserStore} from '../../../stores/userStore';
+
+const StudyView = React.createClass({
+    getInitialState: function() {
+      // We need this because refs are not updated in BootstrapTable.
+      this.refsClone = {};
+      return {
+        data: [],
+        status: "loading",
+        unindexSelected: null,
+        removeSelected: null
+      };
+    },
+
+  componentWillMount: function() {
+    // Subscribe to the store.
+    SearchStore.listen(this._onChange);
+    ResultSelectActions.clear();
+  },
+  componentWillUnmount: function() {
+    console.log("Study Component will umount. ");
+  },
+
+  /**
+   * 2015-09-11:
+   * This method returns a React Component that only has the text and couple of
+   * events (such as click). Today, react-bootstrap-table does not support selectRows
+   * without appear radio ou checkbox.
+   *
+   */
+
+  formatGlobal: function(text, item){
+    let self = this;
+    return (<div onClick={self.onStudyClick.bind(this, item)} className="" style={{"cursor": "pointer"}}>  {text}
+    </div>)
+  },
+  formatStudyDate: function(cell, item){
+    return this.formatGlobal(item.studyDate, item);
+  },
+  formatStudyDescription: function(cell, item){
+    return this.formatGlobal(item.studyDescription, item);
+  },
+  formatInstitutionName: function(cell, item){
+    return this.formatGlobal(item.institutionName, item);
+  },
+  formatModalities: function(cell, item){
+    return this.formatGlobal(item.modalities, item);
+  },
+
+  formatOptions: function(cell, item){
+      let self = this;
+      let isAdmin = UserStore.isAdmin();
+      let unindex = null;
+      let removeFiles = null;
+      if (this.props.enableAdvancedSearch) {
+
+          if (isAdmin) {
+              unindex = (
+                  <button title="Unindex (does not remove file physically)" onClick={self.showUnindex.bind(null, item)}
+                          className="btn btn_dicoogle btn-xs fa fa-eraser"></button>);
+
+              removeFiles = (<button title="Removes the file physically" onClick={self.showRemove.bind(null, item)}
+                                     className="btn btn_dicoogle btn-xs fa fa-trash-o"></button>);
+          }
+          return (<div>
+              {unindex}
+              {removeFiles}
+              {/* plugin-based result options */}
+              <PluginView style={{display: 'inline-block'}} slotId="result-options" data={{
+                  'data-result-type': 'study',
+                  'data-result-uid': item.studyInstanceUID
+                }}/>
+          </div>);
+
+      }
+      return (<div></div>);
+  },
+    handleSelect(item){
+        let {studyInstanceUID} = item;
+        // ResultSelectActions.select(item);
+        let value = this.refsClone[studyInstanceUID].getChecked();
+        if (value)
+            ResultSelectActions.select(item, studyInstanceUID);
+        else
+            ResultSelectActions.unSelect(item, studyInstanceUID);
+
+
+    },
+  handleRefs: function (id, input){
+      this.refsClone[id] = input;
+  },
+  formatSelect: function (cell, item){
+    let {studyInstanceUID} = item;
+    let classNameForIt = "advancedOptions " + studyInstanceUID;
+    return (<div className={classNameForIt}>
+              <Input type="checkbox" label=""
+                    onChange={this.handleSelect.bind(this, item)}
+                    ref={this.handleRefs.bind(this, studyInstanceUID)}/>
+            </div>
+    );
+  },
+
+  sizePerPageListChange(sizePerPage){
+
+  },
+
+  onPageChange(page, sizePerPage) {
+
+  },
+
+	render: function() {
+		var self = this;
+		var resultArray = this.props.patient.studies;
+
+    var selectRowProp = {
+      clickToSelect: true,
+      mode: "none",
+      bgColor: "rgb(163, 210, 216)",
+      onSelect: this.onRowSelect
+    };
+     // TODO trigger this action elsewhere
+    ResultSelectActions.level("study");
+    return (
+        <div>
+            <BootstrapTable data={resultArray} selectRow={selectRowProp} condensed pagination striped hover width="100%">
+            <TableHeaderColumn dataAlign="right" dataField="studyInstanceUID" isKey dataFormat={this.formatStudyDate} dataSort>Date</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="left" dataField="studyDescription" dataFormat={this.formatStudyDescription} dataSort>Description</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="center" dataField="institutionName" dataFormat={this.formatInstitutionName}dataSort>Institution</TableHeaderColumn>
+            <TableHeaderColumn dataAlign="center" dataField="modalities" dataFormat={this.formatModalities} dataSort>Modality</TableHeaderColumn>
+            <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="Opts" isKey={false} dataSort={false} dataFormat={this.formatOptions}>Options</TableHeaderColumn>
+            <TableHeaderColumn hidden={!this.props.enableAdvancedSearch} dataAlign="center" dataField="Select" dataSort dataFormat={this.formatSelect}>#S</TableHeaderColumn>
+            </BootstrapTable>
+          <ConfirmModal show={self.state.unindexSelected !== null}
+                        onHide={self.hideUnindex}
+                        onConfirm={self.onUnindexConfirm.bind(self, self.state.unindexSelected)} />
+          <ConfirmModal show={self.state.removeSelected !== null}
+                        message="The following files will be unindexed and then deleted from their storage."
+                        onHide={self.hideRemove}
+                        onConfirm={self.onRemoveConfirm.bind(self, self.state.removeSelected)} />
+        </div>
+      );
+	},
+  hideUnindex () {
+      if (this.isMounted())
+    this.setState({
+      unindexSelected: null
+    });
+  },
+  showUnindex (item) {
+      if (this.isMounted())
+    this.setState({
+      unindexSelected: item,
+      removeSelected: null
+    });
+  },
+  hideRemove () {
+      if (this.isMounted())
+    this.setState({
+      removeSelected: null
+    });
+  },
+  showRemove (item) {
+      if (this.isMounted())
+    this.setState({
+      removeSelected: item,
+      unindexSelected: null
+    });
+  },
+	extractURISFromData: function(item){
+		var uris = [];
+		for(let ss in item.series)
+			for(let i in item.series[ss].images)
+				uris.push(item.series[ss].images[i].uri);
+		return uris;
+	},
+	onUnindexConfirm: function(item){
+		console.log(item)
+		var uris = this.extractURISFromData(item);
+		let p = this.props.provider;
+
+		ActionCreators.unindex(uris, p);
+	},
+	onRemoveConfirm: function(item){
+		let uris = this.extractURISFromData(item);
+		ActionCreators.remove(uris);
+	},
+	onStudyClick: function(item){
+		this.props.onItemClick(item);
+	},
+  onRowSelect: function(row){
+    this.props.onItemClick(row);
+  },
+  _onChange: function(data){
+
+    if (this.isMounted())
+    {
+      this.setState({data: data.data,
+      status: "stopped",
+      success: data.success,
+      enableAdvancedSearch: data.data.advancedOptions});
+    }
+  }
+});
+
+export {StudyView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/searchResult.jsx b/dicoogle/src/main/resources/webapp/js/components/search/searchResult.jsx
new file mode 100644
index 0000000..f259e84
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/searchResult.jsx
@@ -0,0 +1,265 @@
+import React, {PropTypes} from 'react';
+
+import {PatientView} from './result/patientView';
+import {StudyView} from './result/studyView';
+import {SeriesView} from './result/serieView';
+import {ImageView} from './result/imageView';
+import {ExportView} from './exportView';
+import Webcore from 'dicoogle-webcore';
+import PluginForm from '../plugin/pluginForm.jsx';
+import {DefaultOptions} from '../../constants/defaultOptions';
+import {SearchStore} from '../../stores/searchStore';
+
+const SearchResult = React.createClass({
+
+  propTypes: {
+    requestedQuery: PropTypes.shape({
+      text: PropTypes.string,
+      keyword: PropTypes.bool,
+      other: PropTypes.bool,
+      provider: PropTypes.oneOfType([
+        PropTypes.string,
+        PropTypes.arrayOf(PropTypes.string)
+      ])
+    }).isRequired, // requested query
+    searchOutcome: PropTypes.shape({
+      data: PropTypes.shape({
+        numResults: PropTypes.number,
+        results: PropTypes.array
+      }),
+      error: PropTypes.any
+    }).isRequired,
+    onReturn: PropTypes.func
+  },
+
+  getDefaultProps() {
+    return {
+      onReturn: null
+    }
+  },
+
+  getInitialState: function() {
+    return {
+      showExport: false,
+      showDangerousOptions: DefaultOptions.showSearchOptions,
+      current: 0,
+      batchPlugins: [],
+      currentPlugin: null
+    };
+  },
+
+  componentWillMount: function() {
+    Webcore.fetchPlugins('result-batch', (packages) => {
+      Webcore.fetchModules(packages);
+      this.setState({batchPlugins: packages.map(pkg => ({
+        name: pkg.name,
+        caption: pkg.dicoogle.caption || pkg.name
+      }))});
+    });
+    SearchStore.listen(this._onSearchResult);
+  },
+
+  componentWillUpdate(nextProps) {
+
+    if (this.props.requestedQuery.queryText !== nextProps.requestedQuery.queryText) {
+      //init StepView
+      if(!this.state.current)
+        this.onStepClicked(0);
+    }
+  },
+_onSearchResult: function(outcome) {
+      if (this.isMounted())
+      {
+        this.onStepClicked(0);
+      }
+  },
+  handleClickExport() {
+    this.setState({showExport: true, currentPlugin: null});
+  },
+
+  handleClickBatchPluginButton(plugin) {
+    this.setState({currentPlugin: plugin, showExport: false});
+  },
+
+  handleHideExport() {
+    this.setState({showExport: false});
+  },
+
+  handleHideBatchForm() {
+    this.setState({currentPlugin: null});
+  },
+
+  isLoading() {
+    return !this.props.searchOutcome;
+  },
+
+  getError() {
+    return this.props.searchOutcome.error;
+  },
+
+  render: function() {
+    const {searchOutcome} = this.props;
+
+		if (this.isLoading()){
+      //loading animation
+      return (<div className="loader-inner ball-pulse">
+        <div/>
+        <div/>
+        <div/>
+      </div>);
+		}
+
+    //Check if search failed
+    if(this.getError()) {
+      return (
+        <div>
+          <p>{this.getError()}</p>
+        </div>
+        );
+    }
+    //Check if search return no results
+    if(searchOutcome.data && searchOutcome.data.numResults === 0)
+    {
+      return (
+        <div>
+          <p>No results for that query</p>
+        </div>
+        );
+    }
+
+    const pluginButtons = this.state.batchPlugins.map(plugin =>(
+              <button key={plugin.name} className="btn btn_dicoogle fa dicoogle-webcore-result-batch-button"
+                      onClick={this.handleClickBatchPluginButton.bind(this, plugin)}>
+                {plugin.caption}
+              </button>)
+    );
+
+    let toggleModalClassNames = this.state.showDangerousOptions ? "fa fa-toggle-on" : "fa fa-toggle-off";
+
+    let counters = [];
+    if (this.props.searchOutcome.data) {
+      counters.push(this.props.searchOutcome.data.results.length);
+    }
+    if (this.state.current >= 1 && this.state.patient) {
+      counters.push(this.state.patient.nStudies);
+    }
+    if (this.state.current >= 2 && this.state.study) {
+      counters.push(this.state.study.series.length);
+    }
+    if (this.state.current >= 3 && this.state.serie) {
+      counters.push(this.state.serie.images.length);
+    }
+
+    return (<div className="container-fluid">
+        <div className="row">
+          <Step current={this.state.current} counters={counters} onClick={this.onStepClicked}/>
+        </div>
+        <div id="step-container">
+          {this.getCurrentView()}
+        </div>
+        <button className="btn btn_dicoogle" onClick={this.handleClickExport}><i className="fa fa-download"/>Export</button>
+        <button className="btn btn_dicoogle" onClick={this.toggleAdvOpt}><i className={toggleModalClassNames}/> Advanced Options </button>
+        {pluginButtons}
+        <ExportView show={this.state.showExport} onHide={this.handleHideExport} query={this.props.requestedQuery}/>
+        <PluginForm show={!!this.state.currentPlugin} slotId="result-batch"
+                    plugin={this.state.currentPlugin} onHide={this.handleHideBatchForm}
+                    data={{results: this.props.searchOutcome.data.results}} />
+      </div>);
+	},
+
+  getCurrentView() {
+    let view;
+    switch (this.state.current) {
+      case 0:
+        view = ( <PatientView items={this.props.searchOutcome.data}
+                              provider={this.props.requestedQuery.provider}
+                              enableAdvancedSearch={this.state.showDangerousOptions}
+                              onItemClick={this.onPatientClicked}/>);
+        break;
+      case 1:
+        view = ( <StudyView patient={this.state.patient}
+                            enableAdvancedSearch={this.state.showDangerousOptions}
+                            onItemClick={this.onStudyClicked}/>);
+        break;
+      case 2:
+        view = ( <SeriesView study={this.state.study}
+                             enableAdvancedSearch={this.state.showDangerousOptions}
+                             onItemClick={this.onSeriesClicked}/>);
+        break;
+      case 3:
+        view = ( <ImageView serie={this.state.serie}
+                            enableAdvancedSearch={this.state.showDangerousOptions}/>);
+        break;
+    }
+    return view;
+  },
+
+  onStepClicked: function(stepComponent){
+    this.setState({current: stepComponent});
+  },
+  onPatientClicked: function(patient){
+    this.setState({current: 1, patient, study: null, serie: null});
+  },
+  onStudyClicked: function(study){
+    this.setState({current: 2, study, serie: null});
+  },
+  onSeriesClicked: function(serie){
+    this.setState({current: 3, serie});
+  },
+  toggleAdvOpt: function(){
+    this.setState({showDangerousOptions: !this.state.showDangerousOptions});
+  }
+});
+
+const Step = React.createClass({
+  propTypes: {
+    current: PropTypes.number,
+    counters: PropTypes.arrayOf(PropTypes.number).isRequired
+  },
+  render: function() {
+    const {current, counters: [nPatients, nStudies, nSeries, nImages]} = this.props;
+
+    return (
+        <div className="wizardbar">
+          <div onClick={this.onStepClicked.bind(this, 0)} className={this.getStep(current, 0)}>
+            <div>
+              {nPatients !== undefined && <span className="label label-pill label-primary label-as-badge label-border">{nPatients}</span>}
+                Patient
+            </div>
+          </div>
+          <div onClick={this.onStepClicked.bind(this, 1)} className={this.getStep(current, 1)}>
+            <div>
+              {nStudies !== undefined && <span className="label label-pill label-primary label-as-badge label-border">{nStudies}</span>}
+                Study
+            </div>
+          </div>
+          <div onClick={this.onStepClicked.bind(this, 2)} className={this.getStep(current, 2)}>
+            <div>
+              {nSeries !== undefined && <span className="label label-pill label-primary label-as-badge label-border">{nSeries}</span>}
+                Series
+            </div>
+          </div>
+          <div onClick={this.onStepClicked.bind(this, 3)} className={this.getStep(current, 3)}>
+            <div>
+              {nImages !== undefined && <span className="label label-pill label-primary label-as-badge label-border">{nImages}</span>}
+                Image
+            </div>
+          </div>
+        </div>
+      );
+  },
+  getStep: function(current, step) {
+    if(step === current)
+      return "col-xs-3 wizardbar-item current";
+    else if(step > current)
+      return "col-xs-3 wizardbar-item disabled";
+    else if(step < current)
+      return "col-xs-3 wizardbar-item completed";
+  },
+  onStepClicked: function(current) {
+      this.props.onClick(current);
+  }
+
+});
+
+export {SearchResult};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/searchResultView.jsx b/dicoogle/src/main/resources/webapp/js/components/search/searchResultView.jsx
new file mode 100644
index 0000000..a80e2fc
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/searchResultView.jsx
@@ -0,0 +1,83 @@
+import React, {PropTypes} from 'react';
+
+import {SearchStore} from '../../stores/searchStore';
+import {ActionCreators} from '../../actions/searchActions';
+
+import Webcore from 'dicoogle-webcore';
+import {DefaultOptions} from '../../constants/defaultOptions';
+import {SearchResult} from './searchResult';
+
+
+
+/**
+ * This class is not used anymore.
+ * Deprecated. 
+ */
+const SearchResultView = React.createClass({
+
+  propTypes: {
+    items: PropTypes.shape({
+      text: PropTypes.string,
+      keyword: PropTypes.bool,
+      other: PropTypes.bool,
+      provider: PropTypes.string
+    }).isRequired // the requested query
+  },
+
+  getInitialState: function() {
+    return {
+      data: {}, // {numResults, results}
+      status: "loading",
+      showExport: false,
+      showDangerousOptions: DefaultOptions.showSearchOptions,
+      current: 0,
+      success: undefined,
+      batchPlugins: [],
+      currentPlugin: null
+    };
+  },
+
+  componentDidMount: function() {
+    this.initSearch(this.props.items);
+  },
+
+  componentWillMount: function() {
+    // Subscribe to the store.
+    SearchStore.listen(this._onChange);
+    Webcore.fetchPlugins('result-batch', (packages) => {
+      Webcore.fetchModules(packages);
+      this.setState({batchPlugins: packages.map(pkg => ({
+        name: pkg.name,
+        caption: pkg.dicoogle.caption || pkg.name
+      }))});
+    });
+  },
+
+	initSearch: function(props){
+    ActionCreators.search(props);
+	},
+
+  render: function() {
+    const sOut = {
+      data: this.state.data,
+      error: !this.state.success && 'An error occurred. Please contact your system administrator.'
+    };
+    const rq = this.props.items;
+    return (<SearchResult requestedQuery={rq} searchOutcome={sOut} />);
+	},
+
+  _onChange: function(outcome) {
+    if (this.isMounted())
+    {
+      console.log('outcome:', outcome);
+
+      this.setState({
+        data: outcome.data,
+        status: "stopped",
+        success: outcome.success
+      });
+    }
+  }
+});
+
+export {SearchResultView};
diff --git a/dicoogle/src/main/resources/webapp/js/components/search/searchView.jsx b/dicoogle/src/main/resources/webapp/js/components/search/searchView.jsx
new file mode 100644
index 0000000..4b2d796
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/search/searchView.jsx
@@ -0,0 +1,296 @@
+
+import React, {PropTypes} from 'react';
+import $ from 'jquery';
+import {ActionCreators} from '../../actions/searchActions';
+import {ProvidersStore} from '../../stores/providersStore';
+import {ProvidersActions} from '../../actions/providersActions';
+import {AdvancedSearch} from '../search/advancedSearch';
+import {SearchResult} from '../search/searchResult';
+import {DimFields} from '../../constants/dimFields';
+import {getUrlVars} from '../../utils/url';
+import {SearchStore} from '../../stores/searchStore';
+
+// just a workaround
+var countGlobalEnter = 0;
+const Search = React.createClass({
+    propTypes: {
+      params: PropTypes.object.isRequired,
+      location: PropTypes.object.isRequired
+    },
+
+    getInitialState: function (){
+        this.keyHash = getUrlVars()['_k'];
+        return {
+          label: 'login',
+          searchState: "simple",
+          providers: [],
+          selectedProviders: [],
+          queryText: '',
+          requestedQuery: null,
+          error: null,
+          data: null
+        };
+    },
+
+    componentWillMount: function(){
+      ProvidersStore.listen(this._onProvidersChange);
+      SearchStore.listen(this._onSearchResult);
+    },
+
+    componentDidMount: function(){
+
+      this.enableAutocomplete();
+      this.enableEnterKey();
+
+      if(getUrlVars()['query']) {
+        this.onSearchByUrl();
+      }
+      ProvidersActions.get();
+    },
+    componentWillUnmount: function(){
+      $( "#free_text" ).unbind();
+    },
+    componentWillUpdate: function() {
+
+        if (getUrlVars()['_k'] !== this.keyHash)
+        {
+            this.keyHash = getUrlVars()['_k'];
+            this.setState({
+                requestedQuery: null
+            });
+        }
+        this.keyHash = getUrlVars()['_k'];
+    },
+    componentDidUpdate: function(){
+      
+    },
+
+    onReturn(error) {
+      this.setState({
+        requestedQuery: null,
+        error
+      });
+    },
+
+    getSearchOutcome() {
+      const {data, error} = this.state;
+      return data ? { data, error } : null;
+    },
+
+    render: function() {
+
+      let providersList = this.state.providers.map(
+          (item, index) => (<option key={item} value={item}>
+                              {item}
+                            </option>));
+      providersList.unshift(<option key="__all__" value="__all__">All Providers</option>);
+
+      const currProvider = this.state.selectedProviders[0];
+      let selectionButtons = (
+          <div>
+          <button type="button" className="btn btn_dicoogle" onClick={this.renderFilter} data-trigger="advance-search" id="btn-advance">
+            {this.state.searchState === "simple" ? "Advanced" : "Basic"}
+          </button>
+              <div className="btn-group">
+                  <select id="providersList" className="btn btn_dicoogle form-control"
+                          value={currProvider}
+                          onChange={this.handleProviderSelect}>
+                    {providersList}
+                  </select>
+              </div>
+              </div>
+        );
+
+      let simpleSearchInstance = (
+            <div className="row space_up" id="main-search">
+                    <div className="col-xs-8 col-sm-10">
+                        <input id="free_text" type="text" className="form-control" placeholder="Free text or advanced query"
+                               onChange={this.handleQueryTextChanged} value={this.state.queryText} />
+                    </div>
+                    <div className="col-xs-4 col-sm-2">
+                        <button type="button" className="btn btn_dicoogle" id="search-btn"
+                                onClick={this.onSearchClicked}> <i className="fa fa-search"/>   Search</button>
+                    </div>
+                </div>
+            );
+
+       // if there are already results, we need to add a new component 
+       let resultComponent = false;
+       
+       if (this.state.requestedQuery !== null && !this.state.error) {
+
+         resultComponent = (<SearchResult requestedQuery={this.state.requestedQuery}
+                              searchOutcome={this.getSearchOutcome()}
+                              onReturn={this.onReturn} />);
+       }
+       if(this.state.searchState === "simple") {
+            return (<div>
+              {selectionButtons}
+              {simpleSearchInstance}
+              {resultComponent}
+              <div className="result-error">{this.state.error}</div>
+            </div>);
+       } else if(this.state.searchState === "advanced") {
+            return (<div>
+              {selectionButtons}
+              <AdvancedSearch/>
+              {resultComponent}
+              <div className="result-error">{this.state.error}</div>
+            </div>);
+       }
+    },
+    _onProvidersChange: function(data) {
+        if (this.isMounted())
+        this.setState({providers: data.data});
+    },
+    _onSearchResult: function(outcome) {
+      if (this.isMounted())
+      {
+        console.log('outcome:', outcome);
+
+        let error = null;
+        if (!outcome.success) {
+          error = "An error occurred. Please contact your system administrator.";
+        } else if (outcome.data.numResults === 0) {
+          error = "No studies were found for that search.";
+        }
+        this.setState({
+          data: outcome.data,
+          status: "stopped",
+          success: outcome.success,
+          requestedQuery: error ? null : this.state.requestedQuery,
+          error
+        });
+      }
+    },
+    renderFilter: function(){
+      var switchState;
+      if(this.state.searchState === "simple"){
+        switchState = "advanced";
+      } else {
+        switchState = "simple";
+      }
+      this.setState({searchState: switchState})
+    },
+    onSearchByUrl: function(){
+      let params = {text: getUrlVars()['query'], keyword: getUrlVars()['keyword'], provider: getUrlVars()['provider']};
+      if (params.provider === 'all') {
+        params.provider = undefined;
+      }
+      this.setState({
+        requestedQuery: params
+      });
+    },
+    handleQueryTextChanged(e) {
+      this.setState({queryText: e.target.value});
+    },
+    handleProviderSelect(e) {
+      const name = e.target.value;
+      this.setState({
+        selectedProviders: name === '__all__' ? [] : [name]
+      });
+    },
+    onSearchClicked: function() {
+        const text = this.state.queryText;
+        const provider = this.state.selectedProviders;
+        const params = {text, keyword: this.isKeyword(text), other: true, provider};
+        this.triggerSearch(params);
+    },
+    triggerSearch: function(params){
+        this.setState({
+          requestedQuery: params,
+          data: null,
+          error: null
+        });
+      ActionCreators.search(params);
+    },
+    isKeyword: function(freetext) {
+      return !!freetext.match(/[^\s\\]:\S/);
+    },
+    isAutocompletOpened: function(){
+      if($('.ui-autocomplete').css('display') === 'none'){return false;}
+      return true;
+    },
+
+    enableAutocomplete: function(){
+      function split( val ) {
+        return val.split( /\sAND\s/ );
+      }
+      function extractLast( term ) {
+        return split( term ).pop();
+      }
+
+    $( "#free_text" )
+      // don't navigate away from the field on tab when selecting an item
+      .bind( "keydown", function( event ) {
+      /*  if ( event.keyCode === $.ui.keyCode.TAB &&
+            $( this ).autocomplete( "instance" ).menu.active ) {
+          event.preventDefault();
+        }*/
+        if(event.keyCode === 13){
+          //event.preventDefault();
+          event.stopPropagation();
+        }
+      })
+      .autocomplete({
+        minLength: 0,
+        source: function( request, response ) {
+          // delegate back to autocomplete, but extract the last term
+          response( $.ui.autocomplete.filter(
+            DimFields, extractLast( request.term ) ) );
+
+        },
+        focus: function() {
+          // prevent value inserted on focus
+          return false;
+        },
+        select: function( event, ui ) {
+          var terms = split( this.value );
+          console.log(terms);
+          // remove the current input
+          terms.pop();
+          //if(terms.lenght >1)
+          //terms.join(" AND ");
+          // add the selected item
+          console.log(terms.length);
+          var termtrick = ((terms.length >= 1) ? " AND " : "") + ui.item.value;
+          terms.push(termtrick);
+          // add placeholder to get the colon at the end
+          terms.push( "" );
+          this.value = (terms.join( "" ) + ":");
+
+          return false;
+        }
+      });
+    },
+    
+
+    enableEnterKey: function(){
+      /*$('#free_text').keyup(function(e){
+        if(e.keyCode == 13)
+          {
+            //self.onSearchClicked();
+            console.log("OPENED: ",self.isAutocompletOpened());
+          }
+        });
+        */
+        //
+        //Trick to not search when press enter on autocomplete
+        //
+        
+        $("#free_text").keypress((e) => {
+        if (e.keyCode === 13) {
+            if (++countGlobalEnter >= 1) {
+                console.log("Count: " + countGlobalEnter);
+                this.onSearchClicked();
+                countGlobalEnter = 0;
+                 e.stopPropagation();
+            }
+        }
+    });
+    }
+});
+
+export {Search};
+
+window.action = ActionCreators;
diff --git a/dicoogle/src/main/resources/webapp/js/components/sidebar.js b/dicoogle/src/main/resources/webapp/js/components/sidebar.js
new file mode 100644
index 0000000..a7c600e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/components/sidebar.js
@@ -0,0 +1,50 @@
+
+/*
+ * @author Frederico Silva<fredericosilva at ua.pt>
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+
+import React from 'react';
+import {Link} from 'react-router';
+import {UserStore} from '../stores/userStore';
+
+const Sidebar = React.createClass({
+
+  propTypes: {
+    pluginMenuItems: React.PropTypes.array.isRequired,
+    onLogout: React.PropTypes.func.isRequired
+  },
+
+  render() {
+      console.log("APP RENDER");
+      let menuItems = [
+        {value: "search", caption: "Search", admin: false, icon: 'fa fa-search'},
+        {value: "management", caption: "Management", admin: true, icon: 'fa fa-cogs'},
+        {value: "indexer", caption: "Indexer", admin: true, icon: 'fa fa-file-archive-o'},
+        {value: "about", caption: "About", admin: false, icon: 'fa fa-info'}
+      ].concat(this.props.pluginMenuItems);
+      let isAdmin = UserStore.isAdmin();
+      console.log("Is admin: " + isAdmin)
+
+      let sidebarInstance = (
+        <div>
+          <ul className="sidebar-nav">
+            {
+              menuItems.map(function(e, i) {
+                const to = (e.isPlugin ? '/ext/' : '/') + e.value;
+                  if (!e.admin || isAdmin)
+                    return (<li key={e.value}>
+                      <Link activeClassName="active" to={to}>
+                       <i className={e.icon}/>   {e.caption}
+                      </Link>
+                    </li>);
+              })
+            }
+          </ul>
+        </div>
+        );
+        return sidebarInstance;
+      }
+    });
+
+export default Sidebar;
diff --git a/dicoogle/src/main/resources/webapp/js/constants/defaultOptions.js b/dicoogle/src/main/resources/webapp/js/constants/defaultOptions.js
new file mode 100644
index 0000000..ec93f22
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/constants/defaultOptions.js
@@ -0,0 +1,4 @@
+const DefaultOptions = {
+    showSearchOptions: false
+};
+export {DefaultOptions};
diff --git a/dicoogle/src/main/resources/webapp/js/constants/dimFields.js b/dicoogle/src/main/resources/webapp/js/constants/dimFields.js
new file mode 100644
index 0000000..5548119
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/constants/dimFields.js
@@ -0,0 +1,34 @@
+/* eslint comma-spacing:0 */
+const DimFields = [
+"ModalitiesInStudy"
+,"PerformingPhysicianName"
+,"StudyTime"
+,"NumberOfStudyRelatedInstances"
+,"StudyInstanceUID"
+,"SeriesInstanceUID"
+,"PatientSex"
+,"StudyID"
+,"PerformedLocation"
+,"ManufacturerModelName"
+,"Manufacturer"
+,"PregnancyStatus"
+,"SeriesNumber"
+,"PatientBirthDate"
+,"InstitutionName"
+,"PatientAge"
+,"AccessionNumber"
+,"Priority"
+,"StudyDescription"
+,"ReferringPhysicianName"
+,"OperatorName"
+,"PatientID"
+,"SeriesDescription"
+,"Modality"
+,"InstitutionDepartmentName"
+,"StudyDate"
+,"PatientTelephoneNumbers"
+,"SOPInstanceUID"
+,"PatientName"
+,"SliceLocation"];
+
+export {DimFields};
diff --git a/dicoogle/src/main/resources/webapp/js/constants/endpoints.js b/dicoogle/src/main/resources/webapp/js/constants/endpoints.js
new file mode 100644
index 0000000..8dc3182
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/constants/endpoints.js
@@ -0,0 +1,5 @@
+const Endpoints = {
+  base: process.env.DICOOGLE_BASE_URL || window.location.pathname.slice(1),
+  search: "/search"
+};
+export {Endpoints};
diff --git a/dicoogle/src/main/resources/webapp/js/handlers/requestHandler.js b/dicoogle/src/main/resources/webapp/js/handlers/requestHandler.js
new file mode 100644
index 0000000..7f27fa2
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/handlers/requestHandler.js
@@ -0,0 +1,211 @@
+import {Endpoints} from '../constants/endpoints';
+import $ from 'jquery';
+
+function getPatients(freetext, isKeyword, provider, callbackSucccess, callbackError){
+        console.log("store param: ", freetext);
+        // ??? use dicoogle client?
+
+        //'http://localhost:8080/search?query=wrix&keyword=false&provicer=lucene'
+        if(freetext.length === 0)
+        {
+          freetext = "*:*";
+          isKeyword = true;
+        }
+
+        var url = Endpoints.base + '/searchDIM?query=' + freetext + '&keyword=' + isKeyword;
+        if(provider !== "all")
+        {
+          provider = Array.prototype.concat.apply([], provider);
+          for (const p of provider) {
+            url += "&provider=" + p;
+          }
+        }
+        console.log("store url;", url);
+
+        $.ajax({
+
+          url: url,
+          dataType: 'json',
+          success: function(data) {
+
+            callbackSucccess(data);
+
+          },
+          error: function(xhr, status, err) {
+            callbackError(xhr);
+          }
+        });
+}
+
+function unindex(uri, provider, callbackSuccess, callbackError){
+    console.log("Unindex param: ", uri);
+
+    var url = Endpoints.base + '/management/tasks/unindex';
+    var data = {'uri': uri}
+    if(provider !== 'all')
+      data['provider'] = provider;
+
+    // TODO use dicoogle client
+    $.ajax({
+      url: url,
+      data: data,
+      method: 'post',
+      traditional: true,
+      success: callbackSuccess,
+      error: function(xhr, status, err) {
+        callbackError(xhr);
+      }
+    });
+}
+
+function remove(uri, callbackSucccess, callbackError){
+    console.log("Unindex param: ", uri);
+
+    var url = Endpoints.base + '/management/tasks/remove';
+    var data = {'uri': uri}
+
+    // TODO use dicoogle client
+    $.ajax({
+      url: url,
+      data: data,
+      method: 'post',
+      traditional: true,
+      success: function(data) {
+       callbackSucccess(data);
+      },
+      error: function(xhr, status, err) {
+        callbackError(xhr);
+      }
+    });
+}
+
+function getImageInfo(uid, callbackSucccess, callbackError){
+        console.log("getImageInfo: ", uid);
+
+        //'http://localhost:8080/search?query=wrix&keyword=false&provicer=lucene'
+        var url = Endpoints.base + '/dump?uid=' + uid;
+
+        // TODO use dicoogle client
+        $.ajax({
+          url: url,
+          method: 'get',
+          dataType: 'json',
+          success: function(data) {
+            callbackSucccess(data);
+          },
+          error: function(xhr, status, err) {
+            callbackError(xhr);
+          }
+        });
+}
+
+function getVersion(callbackSucccess, callbackError){
+
+    var url = Endpoints.base + '/ext/version';
+    // TODO use dicoogle client
+    $.ajax({
+        url: url,
+        method: 'get',
+        dataType: 'json',
+        success: function(data) {
+
+            callbackSucccess(data);
+
+        },
+        error: function(xhr, status, err) {
+            callbackError(xhr);
+        }
+    });
+}
+
+function request(url, callbackSucccess, callbackError){
+    console.log("request: " + url);
+    $.ajax({
+
+      url: url,
+      dataType: 'json',
+      success: function(data) {
+
+      callbackSucccess(data);
+
+      },
+      error: function(xhr, status, err) {
+        callbackError(xhr);
+      }
+    });
+}
+
+/*
+INDEXER
+*/
+function setWatcher(state){
+  console.log(state);
+  $.post(Endpoints.base + "/management/settings/index/watcher",
+  {
+    watcher: state
+  },
+    function(data, status){
+      //Response
+      console.log("Data: " + data + "\nStatus: " + status);
+    });
+
+}
+function setZip(state){
+  console.log(state);
+  $.post(Endpoints.base + "/management/settings/index/zip",
+  {
+    zip: state
+  },
+    function(data, status){
+      //Response
+      console.log("Data: " + data + "\nStatus: " + status);
+    });
+
+}
+function setSaveT(state){
+  console.log(state);
+  $.post(Endpoints.base + "/management/settings/index/thumbnail",
+  {
+    thumbnail: state
+  },
+    function(data, status){
+      //Response
+      console.log("Data: " + data + "\nStatus: " + status);
+    });
+
+}
+
+function saveIndexOptions(path, watcher, zip, saveThumbnail, effort, thumbnailSize){
+  //console.log(state);
+  $.post(Endpoints.base + "/management/settings/index",
+  {
+    path: path,
+    watcher: watcher,
+    zip: zip,
+    saveThumbnail: saveThumbnail,
+    effort: effort,
+    thumbnailSize: thumbnailSize
+  },
+    function(data, status){
+      //Response
+      console.log("Data: " + data + "\nStatus: " + status);
+    });
+
+}
+
+function forceIndex(uri){
+  //console.log(state);
+  // TODO use dicoogle client
+  $.post(Endpoints.base + "/management/tasks/index",
+  {
+    uri: uri
+  },
+  function(data, status){
+    //Response
+    console.log("Status:", status);
+  });
+}
+
+export {
+  getPatients, unindex, remove, getImageInfo, request, setWatcher,
+  setZip, setSaveT, saveIndexOptions, forceIndex, getVersion};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/dumpStore.js b/dicoogle/src/main/resources/webapp/js/stores/dumpStore.js
new file mode 100644
index 0000000..2be6fb5
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/dumpStore.js
@@ -0,0 +1,40 @@
+'use strict';
+
+import Reflux from 'reflux';
+import {DumpActions} from '../actions/dumpActions';
+import {getImageInfo} from '../handlers/requestHandler';
+
+const DumpStore = Reflux.createStore({
+    listenables: DumpActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGet: function(data){
+      var self = this;
+      getImageInfo(data,
+        function(data){
+          //SUCCESS
+          console.log("success", data);
+          self._contents = data;
+
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+
+
+    }
+});
+
+export {DumpStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/exportStore.js b/dicoogle/src/main/resources/webapp/js/stores/exportStore.js
new file mode 100644
index 0000000..be3bfb5
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/exportStore.js
@@ -0,0 +1,74 @@
+import Reflux from 'reflux';
+import $ from 'jquery';
+
+import {ExportActions} from '../actions/exportActions';
+import {Endpoints} from '../constants/endpoints';
+import {request} from '../handlers/requestHandler';
+
+const ExportStore = Reflux.createStore({
+    listenables: ExportActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGetFieldList: function(data){
+      var self = this;
+      var url = Endpoints.base + "/export/list";
+      request(url,
+        function(data){
+          //SUCCESS
+          //console.log("success", data);
+          self._contents = data;
+
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+    },
+
+    onExportCSV: function(data, fields){
+
+      let {text, keyword, provider} = data;
+      if(text.length === 0)
+      {
+        text = "*:*";
+        keyword = true;
+      }
+
+      $.ajax({
+        method: "POST",
+        url: Endpoints.base + "/exportFile",
+        traditional: true,
+        data: {
+          query: text,
+          keyword,
+          fields: JSON.stringify(fields),
+          providers: provider
+        }
+      }).then((data, status) => {
+          // create a download link and trigger it automatically
+          const response = JSON.parse(data);
+          const link = document.createElement("a");
+          const hacked_footer = document.getElementById("hacked-modal-footer");
+          link.style.visibility = "hidden";
+          link.download = "file";
+          link.href = Endpoints.base + "/exportFile?UID=" + response.uid;
+          hacked_footer.appendChild(link);
+          link.click();
+          hacked_footer.removeChild(link);
+      });
+
+    }
+});
+
+export {ExportStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/indexStatusStore.js b/dicoogle/src/main/resources/webapp/js/stores/indexStatusStore.js
new file mode 100644
index 0000000..d2c75fe
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/indexStatusStore.js
@@ -0,0 +1,96 @@
+'use strict';
+
+import Reflux from 'reflux';
+import {IndexStatusActions} from '../actions/indexStatusAction';
+import {Endpoints} from '../constants/endpoints';
+import {forceIndex} from '../handlers/requestHandler';
+import $ from 'jquery';
+
+const IndexStatusStore = Reflux.createStore({
+    listenables: IndexStatusActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGet: function(data){
+      var self = this;
+
+      $.ajax({
+        url: Endpoints.base + "/index/task",
+        dataType: 'json',
+        success: function(data) {
+          self._contents = data;
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+
+        },
+        error: function(xhr, status, err) {
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      });
+
+    },
+
+    onStart: function(uri){
+      var self = this;
+      forceIndex(uri);
+
+      self._contents.results.push({taskUid: "...", taskName: uri, taskProgress: -1})
+      self._contents.count = self._contents.count + 1;
+      self.trigger({
+        data: self._contents,
+        success: true
+      });
+
+      console.log(this._contents);
+    },
+
+    onClose: function(uid){
+
+      $.post(Endpoints.base + "/index/task",
+      {
+        uid: uid,
+        action: "delete",
+        type: "close"
+      },
+        function(data, status){
+          //Response
+          console.log("Data: ", data, " ; Status: ", status);
+        });
+
+      for (var i = 0; i < this._contents.results.length; i++)
+      {
+        if (this._contents.results[i].taskUid === uid) {
+          this._contents.results.splice(i, 1);
+          break;
+        }
+      }
+      this.trigger({
+        data: this._contents,
+        success: true
+      });
+    },
+    onStop: function(uid){
+      console.log("Stop: ", uid);
+      $.post(Endpoints.base + "/index/task",
+      {
+        uid: uid,
+        action: "delete",
+        type: "stop"
+      },
+        function(data, status){
+          //Response
+          console.log("Data: ", data, " ; Status: ", status);
+        });
+    }
+
+});
+
+export {IndexStatusStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/indexerStore.js b/dicoogle/src/main/resources/webapp/js/stores/indexerStore.js
new file mode 100644
index 0000000..235d1ee
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/indexerStore.js
@@ -0,0 +1,41 @@
+'use strict';
+
+import Reflux from 'reflux';
+import {IndexerActions} from '../actions/indexerActions';
+import {Endpoints} from '../constants/endpoints';
+import {request} from '../handlers/requestHandler';
+
+const IndexerStore = Reflux.createStore({
+    listenables: IndexerActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGet: function(){
+      console.log("onGet");
+      var self = this;
+      var url = Endpoints.base + "/management/settings/index";
+      request(url,
+        function(data){
+          //SUCCESS
+          console.log("success", data);
+          self._contents = data;
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+
+    }
+});
+
+export {IndexerStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/loggerStore.js b/dicoogle/src/main/resources/webapp/js/stores/loggerStore.js
new file mode 100644
index 0000000..e85fa74
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/loggerStore.js
@@ -0,0 +1,42 @@
+'use strict';
+
+import Reflux from 'reflux';
+import $ from 'jquery';
+import {LoggerActions} from '../actions/loggerActions';
+import {Endpoints} from '../constants/endpoints';
+
+const LoggerStore = Reflux.createStore({
+    listenables: LoggerActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGet: function(data){
+      var self = this;
+
+      $.ajax({
+
+        url: Endpoints.base + "/logger",
+        dataType: 'text',
+        success: function(data) {
+          self._contents = data;
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+
+        },
+        error: function(xhr, status, err) {
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      });
+
+    }
+});
+
+export {LoggerStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/providersStore.js b/dicoogle/src/main/resources/webapp/js/stores/providersStore.js
new file mode 100644
index 0000000..8a1bac5
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/providersStore.js
@@ -0,0 +1,46 @@
+'use strict';
+
+import Reflux from 'reflux';
+import {ProvidersActions} from '../actions/providersActions';
+import {Endpoints} from '../constants/endpoints';
+import {request} from '../handlers/requestHandler';
+
+const ProvidersStore = Reflux.createStore({
+    listenables: ProvidersActions,
+    init: function () {
+       this._providers = [];
+    },
+
+    onGet: function(data){
+      var self = this;
+      if(this._providers.length !== 0)
+      {
+        self.trigger({
+          data: self._providers,
+          success: true
+        });
+        return;
+      }
+
+      request(Endpoints.base + "/providers",
+        function(data){
+          //SUCCESS
+          console.log("success", data);
+          self._providers = data;
+          self.trigger({
+            data: self._providers,
+            success: true
+          });
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+    }
+});
+
+export {ProvidersStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/resultSelected.js b/dicoogle/src/main/resources/webapp/js/stores/resultSelected.js
new file mode 100644
index 0000000..ea8b3b9
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/resultSelected.js
@@ -0,0 +1,64 @@
+'use strict';
+
+import Reflux from 'reflux';
+import ResultSelectActions from '../actions/resultSelectAction';
+
+/**
+ * This list contains the selected results in the UI.
+ * When the user wants to apply an operation in a set of results.
+ */
+const ResultsSelected = Reflux.createStore({
+    listenables: ResultSelectActions,
+    init: function () {
+       this._contents = [];
+       this._level = "";
+    },
+
+    // Change Level
+    onLevel: function (level) {
+       this._level = level;
+    },
+    // Clear the lists, probably changed of level.
+    onClear: function () {
+       this.init();
+    },
+    // A new selection, and so need to store in the list.
+    onSelect: function(data) {
+      console.log("Item: " );
+      console.log(data);
+      console.log(this._contents);
+
+      this._contents.push(data);
+    },
+    onUnSelect (data) {
+        let i = 0;
+        for (var c of this._contents)
+        {
+            if (JSON.stringify(c) === JSON.stringify(data))
+            {
+                this._contents.splice(i, 1);
+                break;
+            }
+            i += 1;
+        }
+    },
+    // Send the batch of selected results to somewhere.
+    onGet: function(data){
+      this.trigger({
+        contents: this._contents,
+        level: this._level
+      });
+    },
+
+    get: function(){
+      console.log(this._contents);
+      console.log(this._level);
+
+      return {
+        contents: this._contents,
+        level: this._level
+      };
+    }
+});
+
+export {ResultsSelected};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/searchStore.js b/dicoogle/src/main/resources/webapp/js/stores/searchStore.js
new file mode 100644
index 0000000..180a849
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/searchStore.js
@@ -0,0 +1,89 @@
+import Reflux from 'reflux';
+
+import {ActionCreators} from '../actions/searchActions';
+
+import {getPatients} from '../handlers/requestHandler';
+import {unindex} from '../handlers/requestHandler';
+import {remove} from '../handlers/requestHandler';
+
+const SearchStore = Reflux.createStore({
+    listenables: ActionCreators,
+    init: function () {
+        this._contents = {advancedOptions: false};
+        //this.listenTo(ActionCreators, "request");
+
+        // subscribe to listen for whole ProductStore first as there is no `waitFor` in Reflux
+        // (https://github.com/voronianski/flux-samples/blob/master/facebook-flux/js/stores/CartStore.js#L55)
+    },
+
+    request: function(url){
+
+    },
+
+    onSearch: function(data){
+      var self = this;
+      getPatients(data.text, data.keyword, data.provider,
+        function(data){
+          //SUCCESS
+          console.log("success", data);
+          data["advancedOptions"] = self._contents.advancedOptions;
+          self._contents = data;
+
+          //Trigger search
+          self.triggerWithDelay()
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+    },
+    onUnindex: function(uris, provider){
+      console.log("fired action");
+      console.log(uris);
+
+      unindex(uris, provider,
+          function() {
+        console.log("sucess");
+      }, function(){
+        console.log("Error");
+      });
+    },
+    onRemove: function(uris){
+      unindex(uris, "all",
+          function() {
+        console.log("sucess");
+      }, function(){
+        console.log("Error");
+      });
+      remove(uris,
+          function() {
+        console.log("sucess");
+      }, function(){
+        console.log("Error");
+      });
+    },
+
+  /* onAdvancedOptionsChange: function(){
+      this._contents.advancedOptions = !this._contents.advancedOptions;
+      this.trigger({
+        data:this._contents,
+        success: true
+      });
+    },
+  */
+    triggerWithDelay: function(){
+      this.trigger({
+        data: this._contents,
+        success: true
+      });
+    }
+
+});
+
+export {SearchStore};
+
+window.store = SearchStore;
diff --git a/dicoogle/src/main/resources/webapp/js/stores/servicesStore.js b/dicoogle/src/main/resources/webapp/js/stores/servicesStore.js
new file mode 100644
index 0000000..fb33d8e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/servicesStore.js
@@ -0,0 +1,166 @@
+import Reflux from 'reflux';
+import ServiceAction from '../actions/servicesAction';
+import {Endpoints} from '../constants/endpoints';
+import {request} from '../handlers/requestHandler';
+import $ from 'jquery';
+
+const ServicesStore = Reflux.createStore({
+    listenables: ServiceAction,
+    init: function () {
+       this._storageRunning = false;
+       this._storagePort = 0;
+       this._storageAutostart = false;
+       this._queryRunning = false;
+       this._queryPort = 0;
+       this._queryAutostart = false;
+
+      this._querySettings = {
+        acceptTimeout: "...",
+        connectionTimeout: "...",
+        idleTimeout: "...",
+        maxAssociations: "...",
+        maxPduReceive: "...",
+        maxPduSend: "...",
+        responseTimeout: "..."
+      };
+
+      this._contents = {
+        storageRunning: false,
+        storagePort: 0,
+        storageAutostart: false,
+        queryRunning: false,
+        queryPort: 0,
+        queryAutostart: false,
+        querySettings: this._querySettings
+       };
+    },
+
+    onGetStorage: function(){
+      request(
+        Endpoints.base + "/management/dicom/storage",
+          (data) => {
+            this._contents.storageRunning = data.isRunning;
+            this._contents.storagePort = data.port;
+            this._contents.storageAutostart = data.autostart;
+            this.trigger(this._contents);
+          },
+          function(error) {
+            console.log("onGetStoreage: failure");
+          }
+      );
+    },
+    onGetQuery: function(){
+      request(
+        Endpoints.base + "/management/dicom/query",
+        (data) => {
+          this._contents.queryRunning = data.isRunning;
+          this._contents.queryPort = data.port;
+          this._contents.queryAutostart = data.autostart;
+          this.trigger(this._contents);
+
+        }, (error) => {
+          console.log("onGetStoreage: failure");
+        }
+      );
+    },
+    onSetStorage: function(state){
+      $.post(Endpoints.base + "/management/dicom/storage",
+      {
+        running: state
+      }, (data, status) => {
+          //Response
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.storageRunning = state;
+          this.trigger(this._contents);
+        });
+
+    },
+    onSetStorageAutostart (enabled) {
+      $.post(Endpoints.base + "/management/dicom/storage",
+      {
+        autostart: enabled
+      },
+        (data, status) => {
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.storageAutostart = enabled;
+          this.trigger(this._contents);
+        });
+    },
+
+    onSetStoragePort(port) {
+      $.post(Endpoints.base + "/management/dicom/storage", {
+        port
+      }, (data, status) => {
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.storagePort = port;
+          this.trigger(this._contents);
+        });
+    },
+
+    onSetQuery: function(state){
+      $.post(Endpoints.base + "/management/dicom/query",
+      {
+        running: state
+      },
+        (data, status) => {
+          //Response
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.queryRunning = state;
+          this.trigger(this._contents);
+
+        });
+    },
+    onSetQueryAutostart (enabled) {
+      $.post(Endpoints.base + "/management/dicom/query",
+      {
+        autostart: enabled
+      }, (data, status) => {
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.queryAutostart = enabled;
+          this.trigger(this._contents);
+      });
+    },
+
+    onSetQueryPort(port) {
+      $.post(Endpoints.base + "/management/dicom/query", {
+        port
+      }, (data, status) => {
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.queryPort = port;
+          this.trigger(this._contents);
+        });
+    },
+
+    onGetQuerySettings: function(){
+      request(
+        Endpoints.base + "/management/settings/dicom/query",
+        (data) => {
+          this._querySettings = data;
+          this._contents.querySettings = this._querySettings;
+          this.trigger(this._contents);
+        }, (error) => {
+          console.log("onGetQuerySettigns: failure");
+        }
+
+      );
+    },
+  onSaveQuerySettings: function(connectionTimeout, acceptTimeout, idleTimeout, maxAssociations, maxPduReceive, maxPduSend, responseTimeout) {
+    $.post(Endpoints.base + "/management/settings/dicom/query",
+    {
+      connectionTimeout,
+      acceptTimeout,
+      idleTimeout,
+      maxAssociations,
+      maxPduReceive,
+      maxPduSend,
+      responseTimeout
+    },
+      (data, status) => {
+        //Response
+        console.log("Data: " + data + "\nStatus: " + status);
+      });
+  }
+
+});
+
+export default ServicesStore;
diff --git a/dicoogle/src/main/resources/webapp/js/stores/storageStore.js b/dicoogle/src/main/resources/webapp/js/stores/storageStore.js
new file mode 100644
index 0000000..9e389b9
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/storageStore.js
@@ -0,0 +1,89 @@
+import Reflux from 'reflux';
+import $ from 'jquery';
+
+import {StorageActions} from '../actions/storageActions';
+import {Endpoints} from '../constants/endpoints';
+
+const StorageStore = Reflux.createStore({
+    listenables: StorageActions,
+    init() {
+       this._contents = [];
+    },
+
+    onGet(data){
+
+      $.ajax({
+        url: Endpoints.base + "/management/settings/storage/dicom",
+        dataType: 'json',
+        success: (data) => {
+          this._contents = data.map((store) => ({
+            aetitle: store.AETitle,
+            ip: store.ipAddrs,
+            port: store.port,
+            description: store.description,
+            public: store.isPublic
+          }));
+          this.trigger({
+            data: this._contents,
+            success: true
+          });
+        },
+        error: (xhr, status, err) => {
+          //FAILURE
+          this.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      });
+
+    },
+    onAdd(aetitle, ip, port, description, isPublic) {
+      console.log("Onadd clicked 2");
+
+      $.post(Endpoints.base + "/management/settings/storage/dicom",
+      {
+        type: "add",
+        aetitle,
+        ip,
+        port,
+        description,
+        public: isPublic
+      },
+      (data, status) => {
+        this._contents.push({aetitle, ip, port, description, public: isPublic});
+        //Response
+        console.log("Data: " + data + "\nStatus: " + status);
+        this.trigger({
+          data: this._contents,
+          success: true
+        });
+      });
+    },
+    onRemove(index) {
+      const {aetitle, ip, port, description} = this._contents[index];
+      const isPublic = this._contents[index].public;
+      $.post(Endpoints.base + "/management/settings/storage/dicom",
+      {
+        type: "remove",
+        aetitle,
+        ip,
+        port,
+        description,
+        public: isPublic
+      },
+      (data, status) => {
+          //Response
+          console.log("Data: " + data + "\nStatus: " + status);
+          this._contents.splice(index, 1);
+          this.trigger({
+            data: this._contents,
+            success: true
+          });
+        });
+
+    }
+
+});
+
+export {StorageStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/transferStore.js b/dicoogle/src/main/resources/webapp/js/stores/transferStore.js
new file mode 100644
index 0000000..b192e06
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/transferStore.js
@@ -0,0 +1,88 @@
+import Reflux from 'reflux';
+import {TransferActions} from '../actions/transferActions';
+import {Endpoints} from '../constants/endpoints';
+import {request} from '../handlers/requestHandler';
+import $ from 'jquery';
+
+const TransferStore = Reflux.createStore({
+    listenables: TransferActions,
+    init: function () {
+       this._contents = {};
+    },
+    getSizeOptions: function() {
+        return Object.keys(this._contents).length;
+    },
+    onGet: function() {
+      console.log("onGet");
+      //Check if store is a non-empty object
+      if(Object.keys(this._contents).length !== 0) {
+        this.trigger({
+          data: this._contents,
+          success: true
+        });
+        return;
+      }
+      let url = Endpoints.base + "/management/settings/transfer";
+      request(url, (data) => {
+          //SUCCESS
+          console.log("success", data);
+          this._contents = data;
+
+          this.trigger({
+            data: this._contents,
+            success: true
+          });
+        }, (xhr) => {
+          //FAILURE
+          this.trigger({
+              success: false,
+              status: xhr.status
+            });
+        });
+    },
+
+    onSelectAll() {
+        this.select(true);
+    },
+    onUnSelectAll() {
+        this.select(false);
+    },
+
+    select(value) {
+        for (let index of this._contents)
+        {
+            for (let indexOptions of index.options)
+            {
+                indexOptions.value = value;
+                this.request(index.uid, indexOptions.name, indexOptions.value);
+            }
+        }
+        this.trigger({
+            data: this._contents,
+            success: true
+        });
+
+    },
+    request(uid, id, value) {
+
+        $.post(Endpoints.base + "/management/settings/transfer", {
+            uid: uid,
+            option: id,
+            value: value
+        }, (data, status) => {
+            //Response
+            console.log("Data: " + data + "\nStatus: " + status);
+        });
+    },
+
+
+    onSet: function(index, indexOption, value){
+      this._contents[index].options[indexOption].value = value;
+      this.trigger({
+        data: this._contents,
+        success: true
+      });
+    }
+});
+
+export {TransferStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/userStore.js b/dicoogle/src/main/resources/webapp/js/stores/userStore.js
new file mode 100644
index 0000000..5ac8a90
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/userStore.js
@@ -0,0 +1,151 @@
+import Reflux from 'reflux';
+import $ from 'jquery';
+import {UserActions} from '../actions/userActions';
+import {Endpoints} from '../constants/endpoints';
+
+import dicoogleClient from 'dicoogle-client';
+
+const UserStore = Reflux.createStore({
+    listenables: UserActions,
+    init: function () {
+       this._contents = {};
+
+       this._isLoggedIn = false;
+       this._username = "";
+       this._isAdmin = false;
+       this._roles = [];
+       this._token = '';
+
+    },
+
+    saveLocalStore: function(){
+        localStorage.setItem("user", JSON.stringify({
+            isAdmin: this._isAdmin,
+            'username': this._username,
+            'roles': this._roles,
+            'token': this._token
+        }));
+
+    },
+    loadLocalStore: function(){
+        if (localStorage.token) {
+            console.log("loadLocalStore");
+            let user = JSON.parse(localStorage.getItem("user"));
+            this._isAdmin = user.isAdmin;
+            this._username = user.username;
+            this._roles = user.roles;
+            this._token = user.token;
+            this._isLoggedIn = true;
+            this.trigger({
+                isLoggedIn: this._isLoggedIn,
+                success: true
+            });
+        }
+    },
+    onLogin: function(user, pass){
+      console.log("onLogin");
+      const self = this;
+
+      let Dicoogle = dicoogleClient(Endpoints.base);
+
+      Dicoogle.login(user, pass, function(errorCallBack, data){
+          if (!data.token)
+          {
+              self.trigger({
+                failed: true
+              });
+              return;
+          }
+          self._username = data.user;
+          self._isAdmin = data.admin;
+          self._token = data.token;
+          self._roles = data.roles;
+          self._isLoggedIn = true;
+          localStorage.token = self._token;
+          self.saveLocalStore();
+
+          console.log("Localstorage token: " + localStorage.token);
+          self.trigger({
+              isLoggedIn: self._isLoggedIn,
+              success: true
+          });
+      });
+
+    },
+
+    onIsLoggedIn: function(){
+
+      if(this._isLoggedIn === false)
+      {
+
+        if (localStorage.token) {
+            this.loadLocalStore();
+            this.trigger({
+                isLoggedIn: self._isLoggedIn,
+                success: true
+            });
+        } else {
+            console.log("Verify ajax");
+
+            $.ajax({
+                type: "GET",
+                url: Endpoints.base + "/login",
+                dataType: 'json',
+                async: true,
+                success: (result) => {
+                /* if result is a JSon object */
+                this._username = result.user;
+                this._isAdmin = result.admin;
+                this._isLoggedIn = true;
+
+                this.saveLocalStore();
+            setTimeout(() => {
+                this.trigger({
+                isLoggedIn: this._isLoggedIn,
+                success: true
+            });
+        }, 500)
+
+        },
+            error: () => {
+                this.trigger({
+                    isLoggedIn: this._isLoggedIn,
+                    success: false
+                });
+            }
+        });
+        }
+
+      } else {
+        //return this._isLoggedIn;
+          if (localStorage.token !== undefined) {
+              this.loadLocalStore();
+              this.trigger({
+                  isLoggedIn: self._isLoggedIn,
+                  success: true
+              });
+          }
+        this.trigger({
+          isLoggedIn: self._isLoggedIn,
+          success: true
+        });
+      }
+    },
+
+    onLogout: function() {
+        delete localStorage.token;
+        delete localStorage.user;
+    },
+
+    getUsername: function(){
+      return this._username;
+    },
+    isAdmin: function(){
+        return this._isAdmin;
+    },
+    getLogginState: function(){
+      return this._isLoggedIn;
+    }
+});
+
+export {UserStore};
diff --git a/dicoogle/src/main/resources/webapp/js/stores/versionStore.js b/dicoogle/src/main/resources/webapp/js/stores/versionStore.js
new file mode 100644
index 0000000..99f60d8
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/stores/versionStore.js
@@ -0,0 +1,37 @@
+import Reflux from 'reflux';
+import {VersionActions} from '../actions/versionAction';
+import {getVersion} from '../handlers/requestHandler';
+
+const VersionStore = Reflux.createStore({
+    listenables: VersionActions,
+    init: function () {
+       this._contents = {};
+    },
+
+    onGet: function(){
+      const self = this;
+      getVersion(
+        function(data){
+          //SUCCESS
+          console.log("success", data);
+          self._contents = data;
+
+          self.trigger({
+            data: self._contents,
+            success: true
+          });
+        },
+        function(xhr){
+          //FAILURE
+          self.trigger({
+              success: false,
+              status: xhr.status
+            });
+        }
+      );
+
+
+    }
+});
+
+export {VersionStore};
diff --git a/dicoogle/src/main/resources/webapp/js/utils/time.js b/dicoogle/src/main/resources/webapp/js/utils/time.js
new file mode 100644
index 0000000..482d997
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/utils/time.js
@@ -0,0 +1,44 @@
+
+/** Split a duration into human-readable parts.
+ *
+ * @param {number} time a number representing the number of milliseconds
+ * @return {array[]} an array representing the parts of the given duration,
+ * in least significant order: ms, s, m, h, d. The returned array will have
+ * a shorter length if the remaining parts are 0 (but the array will always
+ * have at least one element).
+ */
+export function splitTime(time) {
+    const o = [];
+    o.push(time % 1000); // ms
+    time = (time / 1000) | 0;
+    if (time === 0) return o;
+
+    o.push(time % 60) // s
+    time = (time / 60) | 0;
+    if (time === 0) return o;
+
+    o.push(time % 60); // m
+    time = (time / 60) | 0;
+    if (time === 0) return o;
+
+    o.push(time % 24); // h
+    time = (time / 24) | 0;
+    if (time === 0) return o;
+
+    o.push(time); // d
+    return o;
+}
+
+/** Convert a duration into human-readable text
+ * @param {number} timeValue a number representing the number of milliseconds
+ * @return {string} a text representing the duration. Example: "2h 17m 20s 837ms"
+ */
+export function toHumanReadable(timeValue) {
+    const suffix = ['ms', 's', 'm', 'h', 'd'];
+
+    const parts = splitTime(timeValue);
+
+    return parts.map((v, i) =>
+      v + suffix[i]
+    ).reduceRight((pval, cval) => pval + ' ' + cval);
+}
diff --git a/dicoogle/src/main/resources/webapp/js/utils/url.js b/dicoogle/src/main/resources/webapp/js/utils/url.js
new file mode 100644
index 0000000..96edf02
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/js/utils/url.js
@@ -0,0 +1,15 @@
+function getUrlVars()
+{
+   const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
+   let vars = [];
+   let hash;
+   for(var i = 0; i < hashes.length; i++)
+   {
+       hash = hashes[i].split('=');
+       vars.push(hash[0]);
+       vars[hash[0]] = hash[1];
+   }
+   return vars;
+}
+
+export {getUrlVars};
diff --git a/dicoogle/src/main/resources/webapp/package.json b/dicoogle/src/main/resources/webapp/package.json
new file mode 100644
index 0000000..e66b96d
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/package.json
@@ -0,0 +1,108 @@
+{
+  "name": "dicoogle-webapp",
+  "version": "1.3.1",
+  "private": true,
+  "description": "Dicoogle web application",
+  "author": "Universidade de Aveiro, DETI/IEETA, Bioinformatics Group (http://bioinformatics.ua.pt/)",
+  "homepage": "http://www.dicoogle.com",
+  "license": "GPL-3.0+",
+  "keywords": [
+    "dicoogle",
+    "webapp"
+  ],
+  "contributors": [
+    "Luís A. Bastião <bastiao at bmd-software.com>",
+    "Frederico Silva <fredericosilva at ua.pt>",
+    "Eduardo Pinho <eduardopinho at ua.pt>"
+  ],
+  "maintainers": [
+    "Luís A. Bastião <bastiao at bmd-software.com>",
+    "Eduardo Pinho <eduardopinho at ua.pt>"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/bioinformatics-ua/dicoogle"
+  },
+  "main": "js/app.js",
+  "files": [
+    "js/bundle.min.js",
+    "css/",
+    "fonts/",
+    "assets/",
+    "bootstrap/",
+    "lib/",
+    "index.html"
+  ],
+  "engines": {
+    "npm": ">=2.0.0"
+  },
+  "dependencies": {
+    "bootstrap": "^3.3.2",
+    "core-js": "^2.0.3",
+    "dicoogle-client": "^3.6.0",
+    "dicoogle-webcore": "file:../../../../../webcore",
+    "history": "^3.0.0",
+    "jquery": "^1.10.2",
+    "jquery-ui": "~1.10.5",
+    "react": "^0.14.6",
+    "react-addons-update": "^0.14.8",
+    "react-bootstrap": "^0.29.4",
+    "react-bootstrap-table": "^1.4.6",
+    "react-dom": "^0.14.6",
+    "react-font-awesome": "https://github.com/tkurki/react-font-awesome/tarball/master",
+    "react-imageloader": "~2.0.0",
+    "react-router": "^2.0.0-rc5",
+    "react-router-bootstrap": "^0.20.1",
+    "reflux": "^0.3.0"
+  },
+  "devDependencies": {
+    "babel-eslint": "^6.0.4",
+    "babel-preset-es2015": "^6.3.13",
+    "babel-preset-react": "^6.3.13",
+    "babelify": "^7.2.0",
+    "browserify": "^13.0.0",
+    "browserify-shim": "^3.8.2",
+    "envify": "^3.0.0",
+    "eslint": "^2.10.2",
+    "eslint-plugin-import": "^1.8.0",
+    "eslint-plugin-react": "^5.1.1",
+    "gulp": "^3.9.0",
+    "gulp-babel": "^6.1.1",
+    "gulp-eslint": "^2.0.0",
+    "gulp-processhtml": "^1.1.0",
+    "gulp-rename": "^1.2.2",
+    "gulp-rm": "^1.0.0",
+    "gulp-sass": "^2.1.1",
+    "gulp-sourcemaps": "^1.6.0",
+    "gulp-uglify": "^1.5.1",
+    "gulp-util": "^3.0.7",
+    "react-addons-update": "^0.14.8",
+    "vinyl-buffer": "^1.0.0",
+    "vinyl-source-stream": "^1.1.0",
+    "watchify": "^3.7.0"
+  },
+  "scripts": {
+    "prepublish": "gulp production",
+    "build": "gulp production",
+    "js": "gulp js",
+    "css": "gulp css",
+    "css-debug": "gulp css-debug",
+    "html": "gulp html",
+    "debug": "gulp development",
+    "js-debug": "gulp js-debug",
+    "html-debug": "gulp html-debug",
+    "css:watch": "gulp css:watch",
+    "js:watch": "gulp js:watch",
+    "clean": "gulp clean"
+  },
+  "browser": {
+    "bootstrap": "./node_modules/bootstrap/dist/js/bootstrap.js"
+  },
+  "browserify-shim": {
+    "bootstrap": {
+      "depends": [
+        "jquery:jQuery"
+      ]
+    }
+  }
+}
diff --git a/dicoogle/src/main/resources/webapp/run_server b/dicoogle/src/main/resources/webapp/run_server
new file mode 100755
index 0000000..7130a35
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/run_server
@@ -0,0 +1,2 @@
+#!/bin/bash
+python2.7 -m SimpleHTTPServer 9000
diff --git a/dicoogle/src/main/resources/webapp/sass/components/_buttons.scss b/dicoogle/src/main/resources/webapp/sass/components/_buttons.scss
new file mode 100644
index 0000000..bd98bc6
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/_buttons.scss
@@ -0,0 +1,14 @@
+.btn_dicoogle{
+    background-color: $blue1;
+    color: #ffffff;
+    margin-right:5px;
+    &:hover{
+        background-color: $blue4;
+        color: #ffffff;
+    }
+    a{
+      color: #ffffff;
+    }
+
+
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/components/_loaders.scss b/dicoogle/src/main/resources/webapp/sass/components/_loaders.scss
new file mode 100644
index 0000000..e20314b
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/_loaders.scss
@@ -0,0 +1,3 @@
+.ball-pulse > div {
+background-color: $hover_color;
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/components/_step.scss b/dicoogle/src/main/resources/webapp/sass/components/_step.scss
new file mode 100644
index 0000000..de1af18
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/_step.scss
@@ -0,0 +1,252 @@
+.step{
+	height: 45px;
+	padding: 5px;
+	cursor: pointer;
+	margin-bottom: 10px;
+}
+.step.done{
+	background-color: $blue5;
+}
+.step.current{
+	background-color: $blue5;
+	border-color: $blue1;
+	border-style: solid;
+    border-width: 4px;
+
+    -webkit-box-shadow: 5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+    -moz-box-shadow:    5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+    box-shadow:         5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+
+}
+.step.disabled{
+	background-color: $blue6;
+	cursor: default;
+    display: none;
+}
+.stepa{
+    margin-top: 20px;
+	padding: 5px;
+}
+
+.resultRow{
+	&:hover{
+		background-color: $blue6;
+	}
+}
+.table tbody tr:hover td, .table tbody tr:hover th {
+    background-color: $blue6;
+    height:5px;
+    max-height:5px;
+    overflow:hidden;
+}
+
+
+
+.table thead th {
+    background-color: #EEEEEE;
+	color: black;
+    font-style: bold;
+
+}
+
+
+.pagination {
+    li.active {
+        a {
+            background-color: $blue1;
+            &:hover {
+                background: $blue1;
+            }
+            &:focus {
+                background: $blue1;
+            }
+        }
+    }
+    li {
+        a {
+            background-color: $main_color;
+            color: $blue1;
+            &:hover {
+                background: $hover_color;
+            }
+        }
+    }
+}
+/** Advanced Options SASS */
+.advancedOptions {
+    // For select, default padding margins
+    .select {
+        padding: 2px !important;
+        margin-top: 0px;
+        margin-bottom: 0px;
+    }
+    // Define radio values (bootstrap default are not good for this one)
+    .radio {
+        margin-left: 0px;
+    }
+    // Define radio values (bootstrap default are not good for this one)
+    // + checkbox type
+    .form-group{
+        border: none;
+        margin-bottom: 0px;
+
+        text-align: center;
+        padding: 0;
+        white-space: nowrap;
+
+        min-height: 10px;
+        vertical-align: top;
+
+       .radio input[type="radio"],
+       .radio-inline input[type="radio"],
+       .checkbox input[type="checkbox"],
+       .checkbox-inline input[type="checkbox"]
+        {
+            margin-left: -5px;
+            margin-top: 0px;
+            margin-bottom: 0px;
+        }
+    }
+}
+
+
+// Wizard
+/*Theming options - change and everything updates*/
+$wizardSize: 21px;
+
+$bodyColor: white;
+$wizardBGColor: #eeeeee;
+$wizardBGHoverColor: #e6e6e6;
+$currentBGColor: $blue6;
+//$currentBGColor: #3a87ad;
+$currentFontColor:#3a87ad;
+$disableBGColor: #eeeeee;
+$disableFontColor: #999999;
+$completedFontColor: #468847;
+
+
+$paddingVert: .5em; /*don't use more decimals, as it makes browser round errors more likely, make heights unmatching
+-also watch using decimals at all at low wizardSize font sizes!*/
+$paddingSide: 2em;
+$arrowLength: 1em;
+$itemMargin: 2px;
+$bottomMargin: 20px;
+
+$borderRadiusVal: .25em;
+
+.wizardbar {
+  font-size: $wizardSize;
+  line-height: 1;
+ // display: inline-block;
+  margin: 20px 0;
+  width: 100%;
+  border-color: darkgray;
+}
+/*base item styles*/
+.wizardbar-item {
+    display: inline-block;
+    padding: $paddingVert $paddingSide;
+    padding-left: $paddingSide + $arrowLength;
+    text-decoration: none;
+    transition: all .15s;
+
+/*default styles*/
+    background-color: $wizardBGColor;
+    color: $currentFontColor;
+    text-align: center;
+
+    position: relative;
+    //margin-right: $itemMargin;
+    margin-bottom: $bottomMargin;
+    cursor: pointer;
+    border-color: black;
+}
+/*arrow styles*/
+.wizardbar-item:before,
+.wizardbar-item:after {
+    content: "";
+    height: 0;
+    width: 0;
+    border-width: (.5+$paddingVert) 0 (.5+$paddingVert) $arrowLength;
+    border-style: solid;
+    transition: all .15s;
+    position: absolute;
+    left: 100%;
+    top: 0;
+}
+/*arrow overlapping left side of item*/
+.wizardbar-item:before {
+    border-color: transparent transparent transparent black;
+    left: 0;
+}
+/*arrow pointing out from right side of items*/
+.wizardbar-item:after {
+    border-color: transparent transparent transparent white;
+    z-index: 1;
+}
+/*current item styles*/
+.current.wizardbar-item {
+
+    background-color: $currentBGColor;
+    color: $currentFontColor;
+    cursor: pointer;
+}
+.current.wizardbar-item:after {
+    border-color: transparent transparent transparent $currentBGColor;
+}
+
+.disabled.wizardbar-item {
+    background-color: $wizardBGColor;
+    color: $disableFontColor;
+    cursor: not-allowed;
+
+}
+.disabled.wizardbar-item:after {
+    border-color: transparent transparent transparent $disableBGColor;
+}
+
+.completed.wizardbar-item {
+    background-color: $wizardBGColor;
+    color: $completedFontColor;
+    cursor: pointer;
+
+}
+.completed.wizardbar-item:after {
+    border-color: transparent transparent transparent $wizardBGColor;
+}
+
+
+/*hover styles*/
+.wizardbar-item:not(.current):hover {
+    background-color: $wizardBGHoverColor;
+}
+.wizardbar-item:not(.current):hover:after{
+    border-color: transparent transparent transparent $wizardBGHoverColor;
+}
+/*remove arrows from beginning and end*/
+.wizardbar-item:first-of-type:before,
+.wizardbar-item:last-of-type:after
+{
+    border-color: transparent!important;
+}
+/*no inset arrow for first item*/
+.wizardbar-item:first-of-type {
+    border-radius: $borderRadiusVal 0 0 $borderRadiusVal;
+    padding-left: $paddingSide + ($arrowLength/2)
+}
+/*no protruding arrow for last item*/
+.wizardbar-item:last-of-type {
+    border-radius: 0 $borderRadiusVal $borderRadiusVal 0;
+    padding-right: $paddingSide + ($arrowLength/2);
+}
+
+.label-border {
+    margin-bottom: 2px;
+
+
+}
+
+.label-as-badge {
+    border-radius: 1em;
+
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/components/about.scss b/dicoogle/src/main/resources/webapp/sass/components/about.scss
new file mode 100644
index 0000000..c9f35f6
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/about.scss
@@ -0,0 +1,16 @@
+.about{
+  max-width: $app_content_max_width;
+  
+  padding: 30px;
+  justify-content: center;
+  
+}
+
+.gridAbout{
+  margin-top:10px;
+  border: #cdcdcd medium solid;
+  border-radius: 10px;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/components/advancedSearch.scss b/dicoogle/src/main/resources/webapp/sass/components/advancedSearch.scss
new file mode 100644
index 0000000..f563d0a
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/advancedSearch.scss
@@ -0,0 +1,8 @@
+.modalities{
+  width: 200px;
+}
+
+
+.result-error{
+  margin-top: 20px;
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/components/export.scss b/dicoogle/src/main/resources/webapp/sass/components/export.scss
new file mode 100644
index 0000000..eca921a
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/export.scss
@@ -0,0 +1,4 @@
+.exportlist{
+  width:100%; height:400px;
+  
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/components/login.scss b/dicoogle/src/main/resources/webapp/sass/components/login.scss
new file mode 100644
index 0000000..752c532
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/components/login.scss
@@ -0,0 +1,68 @@
+.logincontainer{
+  max-width: 750px;display: block;margin-left: auto;margin-right: auto;
+
+  background-color:rgba(0,0,0,0.2);
+  padding:20px;
+  -webkit-box-shadow: 5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+  -moz-box-shadow:    5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+  box-shadow:         5px 5px 5px 0px rgba(50, 50, 50, 0.75);
+}
+
+.loginlogo{
+  display:block;margin-left: auto; margin-right: auto; margin-top: 30px;
+  width:220px;
+}
+
+.loginA{
+  display:block;
+       width:40%;
+       margin: 0 auto;
+       text-align: center;
+       margin-top: 40px;
+}
+
+.loginTextA{
+  text-align: left; width: 100%;margin-left: 5px;color: black;
+
+}
+.loginInputUsername{
+  width: 100%;margin: 5px;margin-top: 0px;
+}
+.loginInputPassword{
+  width: 100%; margin: 5px;
+}
+
+.loginbody{
+  height:100vh;
+  padding-top:60px;
+  padding-right: 20px;
+  padding-left: 20px;
+  padding-bottom:120px;
+  //background: url(/assets/login_bg.png) no-repeat center center fixed;
+  background-color: $main_color;
+  background-size: cover;
+}
+#footer {
+  //background-color:rgba(0,0,0,0.2);
+	width:100%;
+	height:auto;
+	position:absolute;
+	bottom:0;
+	left:0;
+}
+.footercontainer{
+  max-width:90%;display: block;margin-left: auto;margin-right: auto;
+  align:center;
+
+
+}
+#loginwrapper{
+  min-height:100%;
+  position:relative;
+}
+
+.loginloader{
+  display: block;margin-left: auto;margin-right: auto;
+  width: 0px;
+  margin-top: 30px;
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/core/_colors.scss b/dicoogle/src/main/resources/webapp/sass/core/_colors.scss
new file mode 100644
index 0000000..d3b8f48
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/core/_colors.scss
@@ -0,0 +1,14 @@
+//COLORS
+
+
+$blue1: #008C99;
+$blue2: #0094A0;
+$blue3: #009BA8;
+$blue4: #1BA5B2;
+$blue5: #49AFBB;
+$blue6: #a3d2d8;
+$red: #ff0000;
+
+$main_color: #DFEEF3;
+$hover_color: #A3D2D8;
+$main_bg: #ffffff;
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/core/_dimens.scss b/dicoogle/src/main/resources/webapp/sass/core/_dimens.scss
new file mode 100644
index 0000000..712754e
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/core/_dimens.scss
@@ -0,0 +1 @@
+$app_content_max_width: 3000px;
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/core/_fonts.scss b/dicoogle/src/main/resources/webapp/sass/core/_fonts.scss
new file mode 100644
index 0000000..4e2ebaf
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/core/_fonts.scss
@@ -0,0 +1 @@
+$app-font: lato, "Helvetica Neue",Helvetica,Arial,sans-serif;
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/core/_global.scss b/dicoogle/src/main/resources/webapp/sass/core/_global.scss
new file mode 100644
index 0000000..f373cd4
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/core/_global.scss
@@ -0,0 +1,90 @@
+body {
+    background-color: $main_bg;
+    font-family: $app_font;
+    text-rendering: optimizeLegibility;
+}
+.vertical_center {
+    vertical-align: middle;
+}
+input {
+    margin: 0;
+}
+.inline_block {
+    display: inline-block;
+}
+.globalmargin {
+    margin: 10px;
+}
+.space_up {
+    margin-top: 10px;
+}
+.subject_text {
+    font-size: 17px;
+    color: $blue1;
+    font-weight: bold;
+}
+.centerDivH {
+    margin: 0 auto;
+    display: block;
+}
+.outer {
+    display: table-cell;
+    vertical-align: middle;
+}
+
+.modal{
+  background-color: rgba(0,0,0,0.5);
+}
+
+//FAKE DEFINITIONS
+.resultfake {
+    width: auto !important;
+    height: auto !important;
+    max-width: 100%;
+}
+
+.scrolldiv{
+  white-space: pre-line;
+  overflow-y: auto;
+  //overflow: auto;
+  height: 500px;
+}
+
+.toast {
+    width:200px;
+    height:20px;
+    height: auto;
+    position:absolute;
+    left:50%;
+    margin-left:-100px;
+    bottom:20px;
+    background-color: $blue5;
+    color: #FFFFFF;
+    font-family: Calibri;
+    font-size: 20px;
+    padding:10px;
+    text-align:center;
+    border-radius: 2px;
+    -webkit-box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
+    -moz-box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
+    box-shadow: 0px 0px 24px -1px rgba(56, 56, 56, 1);
+    display:none;
+}
+.testdapissa{
+  height: 400px;
+}
+
+.indexstatusprogress{
+  margin-top: 8px;
+}
+
+.table_text_wrap{
+
+  word-wrap: break-word;
+}
+.table-test{
+  column-width: auto !important;
+}
+.table-dump {
+  min-width: 800px;
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/core/_sections.scss b/dicoogle/src/main/resources/webapp/sass/core/_sections.scss
new file mode 100644
index 0000000..09a3f3f
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/core/_sections.scss
@@ -0,0 +1,17 @@
+#container {
+    max-width: $app_content_max_width;
+    margin: auto;
+    display: flex;
+    padding: 20px;
+    padding-top: 70px;
+    justify-content: center;
+}
+
+
+.dicoogle-webcore-result-options-instance{
+    display:inline-block;
+}
+
+.dicoogle-webcore-result-options{
+    display:inline-block;
+}
\ No newline at end of file
diff --git a/dicoogle/src/main/resources/webapp/sass/dicoogle.scss b/dicoogle/src/main/resources/webapp/sass/dicoogle.scss
new file mode 100644
index 0000000..cf62359
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/dicoogle.scss
@@ -0,0 +1,18 @@
+ at charset "UTF-8";
+
+ at import "core/_colors";
+ at import "core/_fonts";
+ at import "core/_global";
+ at import "core/_dimens";
+ at import "components/_buttons";
+ at import "components/_loaders";
+ at import "components/_step";
+ at import "components/advancedSearch";
+ at import "components/export";
+ at import "components/login";
+ at import "components/about";
+ at import "modules/_user-info";
+ at import "modules/_sidebar";
+ at import "modules/_topbar";
+ at import "modules/_management";
+ at import "core/_sections";
diff --git a/dicoogle/src/main/resources/webapp/sass/modules/_management.scss b/dicoogle/src/main/resources/webapp/sass/modules/_management.scss
new file mode 100644
index 0000000..8f6a3d2
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/modules/_management.scss
@@ -0,0 +1,66 @@
+ at media screen and (max-width: 480px) {
+    .nav {
+        padding-left: 2px;
+        padding-right: 2px;
+    }
+    .nav li {
+        display: block !important;
+        width: 100%;
+        margin: 0px;
+    }
+    .nav li.active {
+        border-bottom: 1px solid #ddd!important;
+        margin: 0px;
+    }
+}
+.nav-pills {
+    li.active {
+        a {
+            background-color: $blue1;
+            &:hover {
+                background: $blue1;
+            }
+            &:focus {
+                background: $blue1;
+            }
+        }
+    }
+    li {
+        a {
+            background-color: $main_color;
+            color: $blue1;
+            &:hover {
+                background: $hover_color;
+            }
+        }
+    }
+}
+.well {
+    background: $main_color;
+}
+
+.list-group-item-management{
+    border-color:$hover_color;
+    border-right-color: white;
+    border-left-color: white;
+}
+
+.panel-primary{
+    .panel-heading{
+ background-color: $hover_color;
+ background-image: none;
+    }
+
+    border-color: $hover_color;
+}
+.indexprogress{
+  width: 40%;
+}
+
+.panel-title{
+    color: $blue1;
+}
+
+.topMargin{
+ margin-top: 30px;
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/modules/_sidebar.scss b/dicoogle/src/main/resources/webapp/sass/modules/_sidebar.scss
new file mode 100644
index 0000000..2bb476b
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/modules/_sidebar.scss
@@ -0,0 +1,29 @@
+#sidebar-wrapper {
+    background-color: $main_color;
+}
+.sidebar-nav {
+    li {
+
+        a {
+            &:hover {
+                background: $blue5;
+            }
+            color:$blue1;
+            font-size:17px;
+            font-weight:bold;
+            text-indent: 5px;
+
+        }
+        i {
+          width: 25px;
+          text-align: center;
+        }
+
+    }
+    margin-top:50px;
+    .active{
+        background: $blue5;
+        color: #ffffff;
+
+    }
+}
diff --git a/dicoogle/src/main/resources/webapp/sass/modules/_topbar.scss b/dicoogle/src/main/resources/webapp/sass/modules/_topbar.scss
new file mode 100644
index 0000000..22045e9
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/modules/_topbar.scss
@@ -0,0 +1,38 @@
+.topbar {
+    width: 100%;
+    height: 50px;
+    background: $blue1;
+    position:fixed;
+    z-index: 1001;
+    line-height: 50px;
+}
+.btn_drawer {
+    width: 50px;
+    height: 50px;
+    background-color: Transparent;
+    background-repeat: no-repeat;
+    border: none;
+    cursor: pointer;
+    overflow: hidden;
+    max-width: 100%;
+    max-height: 100%;
+    padding: 15px
+}
+.topbar {
+    a {
+        height: 50px;
+        color: #ffffff;
+        font-size: 30px;
+        vertical-align: middle;
+    }
+}
+
+.usernameLogin {
+    padding-right: 5px;
+}
+
+
+.buttonLogin {
+    padding-right: 10px;
+}
+
diff --git a/dicoogle/src/main/resources/webapp/sass/modules/_user-info.scss b/dicoogle/src/main/resources/webapp/sass/modules/_user-info.scss
new file mode 100644
index 0000000..d21c3b0
--- /dev/null
+++ b/dicoogle/src/main/resources/webapp/sass/modules/_user-info.scss
@@ -0,0 +1,13 @@
+.user-wrapper {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    padding-bottom: 10px;
+    
+    vertical-align: middle;
+}
+.user-name {
+    font-size: 20px;
+    color: #6CB7C5;
+}
\ No newline at end of file
diff --git a/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestRoles.java b/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestRoles.java
new file mode 100644
index 0000000..9ba5b1c
--- /dev/null
+++ b/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestRoles.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.auth;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import pt.ua.dicoogle.server.users.*;
+import pt.ua.dicoogle.server.web.auth.Authentication;
+import pt.ua.dicoogle.server.web.auth.LoggedIn;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public class TestRoles {
+
+    @Test
+    @Ignore // needs isolation
+    public void testRoles() {
+
+        UsersStruct users = UsersStruct.getInstance();
+        UsersXML usersXML = new UsersXML();
+        users = usersXML.getXML();
+        RolesXML rolesXML = new RolesXML();
+        RolesStruct rolesStruct = rolesXML.getXML();
+        System.out.println(rolesStruct.getRoles());
+    }
+
+    @Test
+    @Ignore // needs isolation
+    public void testUserRoles() {
+
+        RolesXML rolesXML = new RolesXML();
+        RolesStruct rolesStruct = rolesXML.getXML();
+
+        UsersStruct users = UsersStruct.getInstance();
+        UsersXML usersXML = new UsersXML();
+        users = usersXML.getXML();
+        System.out.println(rolesStruct.getRoles());
+        for (User u : users.getUsers())
+        {
+            System.out.println(u.getUsername());
+            for (Role  r : u.getRoles())
+            {
+                System.out.println(r);
+            }
+        }
+
+
+
+    }
+}
diff --git a/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestUsers.java b/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestUsers.java
new file mode 100644
index 0000000..7c2e13c
--- /dev/null
+++ b/dicoogle/src/test/java/pt/ua/dicoogle/core/auth/TestUsers.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.core.auth;
+
+import org.junit.*;
+import pt.ua.dicoogle.server.users.HashService;
+import pt.ua.dicoogle.server.users.User;
+import pt.ua.dicoogle.server.users.UsersStruct;
+import pt.ua.dicoogle.server.users.UsersXML;
+import pt.ua.dicoogle.server.web.auth.Authentication;
+import pt.ua.dicoogle.server.web.auth.LoggedIn;
+
+import static org.junit.Assert.assertEquals;
+import static pt.ua.dicoogle.server.web.servlets.webui.WebUIServlet.camelize;
+
+/**
+ * Created by bastiao on 23/01/16.
+ */
+public class TestUsers {
+
+    @Test
+    @Ignore // needs isolation
+    public void testUsers() {
+
+        UsersStruct users = UsersStruct.getInstance();
+        UsersXML usersXML = new UsersXML();
+        users = usersXML.getXML();
+
+        String username = "nat";
+        boolean admin = false;
+        String passPlainText = "123";
+        String passHash = HashService.getSHA1Hash(passPlainText);             //password Hash
+        String hash = HashService.getSHA1Hash(username + admin + passHash);
+        System.out.println(hash);
+        System.out.println(passHash);
+        User u = new User("nat",hash, admin);
+        users.addUser(u);
+
+
+        for (String uu : users.getUsernames())
+        {
+            System.out.println(users.getUser(uu));
+        }
+
+        Authentication auth = Authentication.getInstance();
+        try {
+            LoggedIn loggedIn = auth.login("nat", "123");
+            System.out.println(loggedIn.getUserName());
+            System.out.println(loggedIn.isAdmin());
+        }
+        catch(Exception e)
+        {
+            System.out.println("Error in the test");
+        }
+
+    }
+
+}
diff --git a/dicoogle/src/test/java/pt/ua/dicoogle/webui/CamelizeTest.java b/dicoogle/src/test/java/pt/ua/dicoogle/webui/CamelizeTest.java
new file mode 100644
index 0000000..3d57331
--- /dev/null
+++ b/dicoogle/src/test/java/pt/ua/dicoogle/webui/CamelizeTest.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle.
+ *
+ * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.webui;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import static pt.ua.dicoogle.server.web.servlets.webui.WebUIServlet.camelize;
+
+/**
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public class CamelizeTest {
+    
+    public CamelizeTest() {
+    }
+    
+    @BeforeClass
+    public static void setUpClass() {
+    }
+    
+    @AfterClass
+    public static void tearDownClass() {
+    }
+    
+    @Before
+    public void setUp() {
+    }
+    
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void theTest() {
+        assertEquals("dicoogleAnnotationEngine", camelize("dicoogle-annotation-engine"));
+        assertEquals("somethingHere", camelize("something-here"));
+        assertEquals("iAmIronMan", camelize("i-am-iron-man"));
+        assertEquals("cantPlayTricksOnMe", camelize("cant-play--tricks---on----me"));
+    }
+}
diff --git a/license.md b/license.md
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/license.md
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5dc2bb0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,127 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>pt.ua.ieeta</groupId>
+  <artifactId>dicoogle-all</artifactId>
+    <version>2.5.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>dicoogle-all</name>
+  
+    <properties>
+        <jetty.version>9.0.3.v20130506</jetty.version>
+        <restlet.version>2.1.2</restlet.version>
+        <dcm4che.version>2.0.29</dcm4che.version>
+        <slf4j.version>1.7.12</slf4j.version>
+    </properties>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+        	<plugin>
+				<groupId>com.mycila</groupId>
+				<artifactId>license-maven-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<header>short-license.txt</header>
+					<includes>
+						<include>**/*.java</include>
+					</includes>
+					<excludes>
+						<exclude>**/package-info.java</exclude>
+					</excludes>
+
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+
+
+
+            <profile>
+                <id>prod-repository</id>
+                <activation>
+                    <property>
+                        <name>!useBmdRepo</name>
+
+                    </property>
+                </activation>
+                <properties>
+
+                </properties>
+                <distributionManagement>
+                    <!-- Versioned releases are published to the releases repository -->
+                    <repository>
+                        <id>mi</id>
+                        <url>http://bioinformatics.ua.pt/maven/content/repositories/mi</url>
+                    </repository>
+
+
+                    <!-- Snapshot releases are published to the snapshots repository -->
+                    <snapshotRepository>
+                        <id>mi</id>
+                        <url>http://bioinformatics.ua.pt/maven/content/repositories/mi-snapshots</url>
+                    </snapshotRepository>
+                </distributionManagement>
+
+            </profile>
+        <profile>
+            <id>bmd-repository</id>
+            <activation>
+                <property>
+                    <name>useBmdRepo</name>
+                    <value>true</value>
+                </property>
+            </activation>
+
+
+            <properties>
+
+            </properties>
+            <distributionManagement>
+            <!-- Versioned releases are published to the releases repository -->
+            <repository>
+                <id>bmdsoftware-releases</id>
+                <name>BMD Software Nexus (Internal Releases)</name>
+                <url>https://dev.bmd-software.com/nexus/content/repositories/releases</url>
+            </repository>
+            <!-- Snapshot releases are published to the snapshots repository -->
+            <snapshotRepository>
+                <id>bmdsoftware-snapshots</id>
+                <name>BMD Software Nexus (Internal Snapshots)</name>
+                <url>https://dev.bmd-software.com/nexus/content/repositories/snapshots</url>
+            </snapshotRepository>
+            </distributionManagement>
+
+        </profile>
+    </profiles>
+
+    <distributionManagement>
+
+
+
+
+
+    </distributionManagement>
+
+    <modules>
+        <module>dicoogle</module>
+        <module>sdk</module>
+        <module>sdk-ext</module>      
+    </modules>
+</project>
diff --git a/sdk-ext/.gitignore b/sdk-ext/.gitignore
new file mode 100644
index 0000000..71018fd
--- /dev/null
+++ b/sdk-ext/.gitignore
@@ -0,0 +1,2 @@
+/target
+/dependency-reduced-pom.xml
diff --git a/sdk-ext/pom.xml b/sdk-ext/pom.xml
new file mode 100644
index 0000000..b24f0d0
--- /dev/null
+++ b/sdk-ext/pom.xml
@@ -0,0 +1,163 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>dicoogle-sdk-ext</artifactId>
+	<packaging>jar</packaging>
+	<name>dicoogle-sdk-ext</name>
+	<url>http://www.dicoogle.com</url>
+
+        <parent>
+            <groupId>pt.ua.ieeta</groupId>
+            <artifactId>dicoogle-all</artifactId>
+			<version>2.5.0-SNAPSHOT</version>
+            <relativePath>../pom.xml</relativePath>
+        </parent>
+
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<repositories>
+
+		<repository>
+			<id>mavencentral</id>
+			<url>http://repo1.maven.org/maven2/</url>
+			<snapshots>
+				<enabled>true</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+
+	<build>
+		<finalName>${project.artifactId}</finalName>
+		<plugins>
+			<plugin>
+                            <groupId>org.apache.maven.plugins</groupId>
+                            <artifactId>maven-shade-plugin</artifactId>
+                            <version>2.3</version>
+                            <executions>
+                                <execution>
+                                    <phase>package</phase>
+                                    <goals>
+                                        <goal>shade</goal>
+                                    </goals>
+                                    <configuration>
+                                            <artifactSet>
+                                                <excludes>
+                                                    <exclude>org.dicoogle.sdk:dicoogle-sdk</exclude>
+                                                </excludes>
+                                            </artifactSet>
+                                            <filters>
+                                                <filter>
+                                                    <artifact>*:*</artifact>
+                                                    <excludes>
+                                                        <exclude>**/*.SF</exclude>
+                                                        <exclude>**/*.DSA</exclude>
+                                                        <exclude>**/*.RSA</exclude>
+                                                    </excludes>
+                                                </filter>
+                                            </filters>
+                                    </configuration>
+                                </execution>
+                            </executions>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+                                <version>2.3</version>
+				<configuration>
+					<systemProperties>
+					</systemProperties>
+				</configuration>
+			</plugin>
+
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<encoding>${project.build.sourceEncoding}</encoding>
+					<source>1.7</source>
+					<target>1.7</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<version>2.4.3</version>
+				<configuration>
+					<encoding>${project.build.sourceEncoding}</encoding>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>com.mycila</groupId>
+				<artifactId>license-maven-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<header>../short-license.txt</header>
+					<includes>
+						<include>**/*.java</include>
+					</includes>
+					<excludes>
+						<exclude>**/package-info.java</exclude>
+					</excludes>
+
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>check</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.8.1</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>pt.ua.ieeta</groupId>
+			<artifactId>dicoogle-sdk</artifactId>
+                        <version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>dom4j</groupId>
+			<artifactId>dom4j</artifactId>
+			<version>1.6.1</version>
+		</dependency>
+                
+                <dependency>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                    <version>${slf4j.version}</version>
+                </dependency>
+
+	</dependencies>
+    <distributionManagement>
+
+        <!-- Versioned releases are published to the releases repository -->
+        <repository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi</url>
+        </repository>
+
+
+        <!-- Snapshot releases are published to the snapshots repository -->
+        <snapshotRepository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi-snapshots</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+
+</project>
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GenericPluginInterface.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GenericPluginInterface.java
new file mode 100755
index 0000000..4cb4875
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GenericPluginInterface.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import net.xeoh.plugins.base.Plugin;
+import pt.ua.dicoogle.sdk.Utils.TaskQueue;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.FileObservable;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public interface GenericPluginInterface extends Plugin
+{
+    public void attendTask(TaskRequest task);
+    
+    //public ListObservable<TaskRequest> getTaskRequestsList();
+
+    //public ListObservable<SearchResult> getResults();
+
+    public String getName();
+
+    public void initialize(TaskQueue tasks);
+
+    public void Stop();
+
+    /**
+     * Although these methods return an observable, it is mandatory that the local indexes return the array with the results...
+     * @param query
+     * @param extrafields
+     * @return
+     */
+    
+    public ListObservableSearch<SearchResult> search(String query, Collection<String> extrafields);
+    public ListObservableSearch<SearchResult> searchOne(String query, Collection<String> Extrafields, String address);
+    public FileObservable requestFile(String address, String name, String hash);
+
+    public boolean isLocalPlugin();
+
+    public void setDefaultSettings();
+
+    public void setSettings(ArrayList<Object> settings);
+
+    public ArrayList<Object> getPanelInitilizationParams();
+
+    //public PluginPanel getConfigPanel();
+
+    //public void setSettings(PluginPanel settings);
+
+    public boolean isRunning();
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GraphicPluginAdapter.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GraphicPluginAdapter.java
new file mode 100755
index 0000000..cab9ed9
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/GraphicPluginAdapter.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+/**
+ *
+ * @author bastiao
+ */
+public interface GraphicPluginAdapter extends GenericPluginInterface
+{
+    
+    public void initGUI();
+    
+}
+  
\ No newline at end of file
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/NetworkPluginAdapter.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/NetworkPluginAdapter.java
new file mode 100755
index 0000000..4bd18fd
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/NetworkPluginAdapter.java
@@ -0,0 +1,212 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import org.slf4j.LoggerFactory;
+import pt.ua.dicoogle.sdk.Utils.QueryNumber;
+import pt.ua.dicoogle.sdk.Utils.TaskQueue;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.FileObservable;
+import pt.ua.dicoogle.sdk.observables.ListObservable;
+import pt.ua.dicoogle.sdk.observables.ListObservableSearch;
+import pt.ua.dicoogle.sdk.observables.MessageObservable;
+import pt.ua.dicoogle.sdk.p2p.Messages.Builders.MessageBuilder;
+import pt.ua.dicoogle.sdk.p2p.Messages.Handlers.MainMessageHandler;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public abstract class NetworkPluginAdapter implements GenericPluginInterface, Observer
+{
+
+    private boolean isRunning = false;
+    protected MainMessageHandler MMH;
+    private ListObservableSearch<SearchResult> searchResults = new ListObservableSearch<>();
+    private TaskQueue TaskRequestsList;
+    private MessageObservable mo;
+    private List<FileObservable> requestedFiles = Collections.synchronizedList(new ArrayList<FileObservable>());
+
+    @Override
+    public abstract String getName();
+
+    public abstract NetworkPluginAdapter getInstance();
+
+    public abstract MessageObservable initialize();
+
+    public abstract void connect();
+
+    public abstract void disconnect();
+
+    public abstract boolean isConnected();
+
+    public abstract void send(Object message);
+
+    public abstract void send(Object toSend, String address);
+
+    public abstract void sendFile(String path, String destAddress);
+
+    public abstract ListObservableSearch<String> getMembers();
+
+    public abstract String getLocalAddress();
+
+    protected abstract MessageObservable getLastmessage();
+
+    public List<FileObservable> getRequestedFiles()
+    {
+        return this.requestedFiles;
+    }
+
+    public TaskQueue getTaskRequestsList()
+    {
+        return TaskRequestsList;
+    }
+
+    @Override
+    public void attendTask(TaskRequest task)
+    {
+    }
+
+    @Override
+    public void initialize(TaskQueue tasks)
+    {
+        //System.out.println("NetworkPluginAdapter initialize");
+        this.isRunning = true;
+        this.TaskRequestsList = tasks;
+        mo = getInstance().initialize();
+        mo.addObserver(getInstance());
+        this.MMH = new MainMessageHandler(this);
+    }
+
+    @Override
+    public void Stop()
+    {
+        mo.deleteObserver(getInstance());
+        this.isRunning = false;
+        this.disconnect();
+    }
+
+    @Override
+    public ListObservableSearch<SearchResult> search(String query, Collection<String> extrafields)
+    {
+        MessageBuilder mb = new MessageBuilder();
+        MessageI message = null;
+        try
+        {
+            Integer qNumber;
+            synchronized (this.searchResults)
+            {
+                qNumber = QueryNumber.getInstance().getNewQueryNumber();
+                this.searchResults.resetArray();
+            }
+            message = mb.buildQueryMessage(query, extrafields, this.getName(), qNumber);
+        } catch (IOException ex)
+        {
+            LoggerFactory.getLogger(NetworkPluginAdapter.class).error(ex.getMessage(), ex);
+            return null;
+        }
+
+        send(message);
+        return this.searchResults;
+    }
+
+    @Override
+    public ListObservableSearch<SearchResult> searchOne(String query, Collection<String> Extrafields, String address)
+    {
+        MessageBuilder mb = new MessageBuilder();
+        MessageI message = null;
+        try
+        {
+            Integer qNumber;
+            synchronized (this.searchResults)
+            {
+                qNumber = QueryNumber.getInstance().getNewQueryNumber();
+                this.searchResults.resetArray();
+            }
+            message = mb.buildQueryMessage(query, Extrafields, this.getName(), qNumber);
+        } catch (IOException ex)
+        {
+            LoggerFactory.getLogger(NetworkPluginAdapter.class).error(ex.getMessage(), ex);
+            return null;
+        }
+
+        send(message, address);
+        return this.searchResults;
+    }
+
+    @Override
+    public FileObservable requestFile(String address, String name, String hash)
+    {
+        MessageBuilder mb = new MessageBuilder();
+        MessageI message = null;
+        try
+        {
+            message = mb.buildFileRequest(name, hash, this.getName());
+        } catch (IOException ex)
+        {
+            LoggerFactory.getLogger(NetworkPluginAdapter.class).error(ex.getMessage(), ex);
+            return null;
+        }
+        FileObservable newFileObservable = new FileObservable(address, name);
+        this.requestedFiles.add(newFileObservable);
+        send(message, address);
+        return newFileObservable;
+    }
+
+    @Override
+    public boolean isLocalPlugin()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isRunning()
+    {
+        return this.isRunning;
+    }
+
+    @Override
+    public void update(Observable o, Object arg)
+    {
+        //System.out.println("NetworkPluginPanel....some message received..."+ o.toString());
+        if (MessageObservable.class.isInstance(o))
+        {
+            MessageObservable message = (MessageObservable) o;
+            //System.out.println("NPA....received the message:\n"+ message);
+            this.MMH.handleMessage((MessageI) message.getMessage(), message.getAddress());
+            
+        }
+    }
+
+    public ListObservable<SearchResult> getSearchResults()
+    {
+        return searchResults;
+    }
+    
+    
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/Platform.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/Platform.java
new file mode 100755
index 0000000..44dbc8d
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/Platform.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import org.slf4j.LoggerFactory;
+import javax.swing.filechooser.FileSystemView;
+
+/**
+ * Detect which platform is running
+ * @author Lu??s A. Basti??o Silva <bastiao at ua.pt>
+ */
+public class Platform
+{
+
+    public  enum MODE {PORTABLE, BUNDLE};
+
+    public static MODE getMode()
+    {
+        MODE mode = MODE.PORTABLE;
+        File currentDir = new File (".");
+        File bundle = new File("BUNDLE.here");
+        File windows = new File("Java Launcher.exe");
+        File mac = new File("Dicoogle.app");
+        if (currentDir.getAbsolutePath().contains("Dicoogle.app")|| bundle.exists()||mac.exists()||windows.exists())
+        {
+            mode = MODE.BUNDLE;
+        }
+        return mode;
+    }
+
+    public static String homePath()
+    {
+
+        String homePath = "";
+        MODE mode = getMode();
+        if (mode==MODE.BUNDLE)
+        {
+            homePath = getHomeDirectory().getAbsolutePath() + File.separator + ".dicoogle" + File.separator;
+        }
+        return homePath;
+    }
+
+    public static File getHomeDirectory()
+    {
+
+        File result = null;
+        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1)
+        {
+            try {
+                Process p = Runtime.getRuntime().exec("cmd /c echo %HOMEDRIVE%%HOMEPATH%");
+                BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+                try {
+                    p.waitFor();
+                } catch (InterruptedException e) {
+                    throw new IOException("Interrupted: " + e.getMessage());
+                }
+                result = new File(reader.readLine());
+            } catch (IOException ex) {
+                LoggerFactory.getLogger(Platform.class.getName()).error(ex.getMessage(), ex);
+            }
+        }
+        else
+        {
+            result = FileSystemView.getFileSystemView().getHomeDirectory();
+        }
+        return result ;
+	
+    }
+
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/PluginPanel.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/PluginPanel.java
new file mode 100755
index 0000000..ade0460
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/PluginPanel.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+import java.util.ArrayList;
+import net.xeoh.plugins.base.Plugin;
+
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public interface PluginPanel extends Plugin
+{
+    public void initialize(ArrayList<Object> params);
+    public ArrayList<Object> getProperties();
+    public String getPluginName();
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/QueryNumber.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/QueryNumber.java
new file mode 100755
index 0000000..a7ee0a3
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/QueryNumber.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+/**
+ * Class to provides a unique ID to a query.
+ * This class solves the problem, caused when the user search for two different things
+ * without receive every responses of the other peers. There is only one query active at a time.
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class QueryNumber
+{
+    private static Integer queryNumber;
+    private static QueryNumber instance = null;
+
+    public static QueryNumber getInstance()
+    {
+        if (instance == null)
+        {
+            instance = new QueryNumber();
+        }
+        return instance;
+    }
+
+    private QueryNumber()
+    {
+        queryNumber = new Integer(0);
+    }
+
+    public Integer getNewQueryNumber()
+    {
+        return ++queryNumber;
+    }
+
+    public Integer getQueryNumber()
+    {
+        return queryNumber;
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskQueue.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskQueue.java
new file mode 100755
index 0000000..9da276c
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskQueue.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+import java.util.Observable;
+import java.util.Queue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class TaskQueue extends Observable
+{
+    private Queue<TaskRequest> tasks;
+
+    public TaskQueue()
+    {
+        tasks = new LinkedBlockingQueue<TaskRequest>();
+    }
+
+    public synchronized void addTask(TaskRequest newTask)
+    {
+        this.tasks.add(newTask);
+        this.setChanged();
+        this.notifyObservers();
+    }
+
+    public synchronized TaskRequest getNextTask()
+    {
+        return this.tasks.poll();
+    }
+
+    public synchronized boolean isEmpty()
+    {
+        return this.tasks.isEmpty();
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequest.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequest.java
new file mode 100755
index 0000000..8ed9feb
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequest.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+import java.util.Map;
+import java.util.Observable;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class TaskRequest extends Observable
+{
+    private int Task;
+    private String RequesterPlugin;
+    private Map<Integer, Object> Parameters;
+    private Map<Integer, Object> results;
+    private boolean completed;
+
+    public TaskRequest(int Task, String RequesterPlugin, Map<Integer, Object> Parameters)
+    {
+        this.Task = Task;
+        this.RequesterPlugin = RequesterPlugin;
+        this.Parameters = Parameters;
+        this.completed = false;
+        this.results = null;
+    }
+
+    public Map<Integer, Object> getParameters()
+    {
+        return Parameters;
+    }
+
+    public String getRequesterPlugin()
+    {
+        return RequesterPlugin;
+    }
+
+    public int getTask()
+    {
+        return Task;
+    }
+
+    public Map<Integer, Object> getResults()
+    {
+        return results;
+    }
+
+    
+    public void completeTask()
+    {
+        this.completed = true;
+    }
+
+    public boolean isCompleted()
+    {
+        return this.completed;
+    }
+    
+    public void setResults(Map<Integer, Object> results)
+    {
+        this.results = results;
+        
+        //notification of the observers.
+        this.setChanged();
+        this.notifyObservers();
+    }
+
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequestsConstants.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequestsConstants.java
new file mode 100755
index 0000000..94fb0f5
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/Utils/TaskRequestsConstants.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.Utils;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class TaskRequestsConstants
+{
+    //Task Types
+    public static final int T_QUERY_LOCALLY = 1;
+    public static final int T_INDEX_FILE = 2;
+    //public static final int T_INDEX_UPDATE = 3;
+    public static final int T_LOGGER_MESSAGE_ALREADY_INDEXED = 4;
+    public static final int T_RESET_LOCAL_INDEX = 5;
+    public static final int T_LOCAL_DELETE_FILE = 6;
+    public static final int T_QUERY_PRUNE = 7;
+    public static final int T_BLOCK_SIGNAL = 8;
+    
+    //Task Parameters
+    public static final int P_QUERY = 1;
+    public static final int P_EXTRAFIELDS = 2;
+    public static final int P_REQUESTER_ADDRESS = 3;
+    public static final int P_QUERY_NUMBER = 4;
+    public static final int P_FILE_PATH = 5;
+    public static final int P_MESSAGE = 6;
+    public static final int P_TO_REMOVE_FILE = 7;
+    
+    
+    
+    //Task Results
+    public static final int R_SEARCH_RESULTS = 1;
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomByteArrField.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomByteArrField.java
new file mode 100755
index 0000000..0b9e3f0
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomByteArrField.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class DicomByteArrField implements IDicomField
+{
+ 
+    private String name;
+    private byte [] value;
+    
+
+    public DicomByteArrField(String name, byte [] value)
+    {
+        this.name = name;
+        this.value = value;
+        
+    }
+    
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the value
+     */
+    public  byte [] getValue() {
+        return value;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setValue(byte [] value) {
+        this.value = value;
+    }
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomDocument.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomDocument.java
new file mode 100755
index 0000000..e82ca7c
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomDocument.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class DicomDocument implements IDoc
+{
+    
+    private List<IDicomField> dicomFields = new ArrayList<IDicomField>();
+
+    public void add(String name, String value) 
+    {
+        this.getDicomFields().add(new DicomTextField(name, value));
+    }
+
+    
+    public void add(String name, Float value) {
+        this.getDicomFields().add(new DicomNumericField(name, value));
+    }
+
+    public void add(String name, byte[] value) {
+        this.getDicomFields().add(new DicomByteArrField(name, value));
+    }
+    
+    /**
+     * @return the dicomFields
+     */
+    public List<IDicomField> getDicomFields() {
+        return dicomFields;
+    }
+
+    /**
+     * @param dicomFields the dicomFields to set
+     */
+    public void setDicomFields(List<IDicomField> dicomFields) {
+        this.dicomFields = dicomFields;
+    }
+
+
+    
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomNumericField.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomNumericField.java
new file mode 100755
index 0000000..02100bd
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomNumericField.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class DicomNumericField implements IDicomField
+{
+ 
+    private String name;
+    private Float value;
+    
+
+    public DicomNumericField(String name, Float value)
+    {
+        this.name = name;
+        this.value = value;
+        
+    }
+    
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the value
+     */
+    public Float getValue() {
+        return value;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setValue(Float value) {
+        this.value = value;
+    }
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomTextField.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomTextField.java
new file mode 100755
index 0000000..77dd6c9
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/DicomTextField.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class DicomTextField implements IDicomField
+{
+ 
+    private String name;
+    private String value;
+    
+
+    public DicomTextField(String name, String value)
+    {
+        this.name = name;
+        this.value = value;
+        
+    }
+    
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the value
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDicomField.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDicomField.java
new file mode 100755
index 0000000..376e33a
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDicomField.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+/**
+ *
+ * @author bastiao
+ */
+public interface IDicomField {
+    
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDoc.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDoc.java
new file mode 100755
index 0000000..3fa6e65
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IDoc.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+import java.util.List;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface IDoc 
+{
+    public void add(String name, String value);
+    public void add(String name, Float value);
+    public void add(String name, byte [] value);
+    
+    public List<IDicomField> getDicomFields();
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IndexPluginInterface.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IndexPluginInterface.java
new file mode 100755
index 0000000..bfad791
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/IndexPluginInterface.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+import java.util.List;
+import java.util.Set;
+import pt.ua.dicoogle.sdk.GenericPluginInterface;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ * This interface contains all methods to be implemented for Core entities.
+ * All Index extensions and IndexEngine should implement it
+ *
+ * 
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface IndexPluginInterface extends GenericPluginInterface
+{
+    public  void index(IDoc doc);
+    public void index(List<IDoc> docs);
+    public void optimize();
+    
+    public List<SearchResult> searchSync(String query,  List<String> extrafields);
+    
+    public Set<String> enumField(String fieldName, boolean isFloat);
+    public int countResults(String query);
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/LongField.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/LongField.java
new file mode 100755
index 0000000..f1efc7d
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/LongField.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class LongField implements IDicomField
+{
+ 
+    private String name;
+    private Long value;
+    
+
+    public LongField(String name, Long value)
+    {
+        this.name = name;
+        this.value = value;
+        
+    }
+    
+    
+    /**
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the value
+     */
+    public Long getValue() {
+        return value;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setValue(Long value) {
+        this.value = value;
+    }
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandler.java
new file mode 100755
index 0000000..f85811e
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandler.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index.handlers;
+
+import java.io.File;
+import pt.ua.dicoogle.sdk.index.IDoc;
+
+/**
+ * General interface to return a Lucene Document
+ * @author Marco
+ */
+public interface DocumentHandler
+{
+    IDoc getDocument(File file) throws DocumentHandlerException, FileAlreadyExistsException;
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandlerException.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandlerException.java
new file mode 100755
index 0000000..f9ac8b9
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/DocumentHandlerException.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index.handlers;
+
+/**
+ * DocumentHandler Exception.
+ * @author marco
+ */
+public class DocumentHandlerException extends Exception {
+    
+	/**
+	 * Generic exception
+	 */
+    public DocumentHandlerException()
+    {
+        super();
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/ExtensionFileHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/ExtensionFileHandler.java
new file mode 100755
index 0000000..1f9eb82
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/ExtensionFileHandler.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index.handlers;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import pt.ua.dicoogle.sdk.index.IDoc;
+
+
+
+/**
+ * Handles different filetypes based on information from Properties
+ * Lmitation : The file must have an extension of any form
+ * @author marco
+ */
+public class ExtensionFileHandler {
+
+    private Properties handlerProps;
+    
+    /**
+     * Creates a new Extension File Handler
+     * @param p Properties that allow the correct class to be called for each extension
+     */
+    public ExtensionFileHandler(Properties p) throws IOException
+    {
+        handlerProps = p;
+    }
+    
+    /**
+     * Handle a file, obtaining a Lucene Document from it, if it
+     * knows how to process this file type. Since we are interest in
+     * indexing files, the path is also saved as a field
+     * @param file File to be handled
+     * @return Lucene Friendly Document
+     */
+    public IDoc getDocument(File file) throws FileHandlerException, FileAlreadyExistsException {
+        IDoc doc = null;
+        String name = file.getName();
+        String Error = "Cannot create instance of : ";
+        if (name.contains(".DS_Store"))
+        {
+            return null;
+        }
+        try
+        {
+            Class handlerClass = Class.forName("pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG");
+            DocumentHandler handler = (DocumentHandler) handlerClass.newInstance();
+            doc = handler.getDocument(file);
+        }
+        catch (DocumentHandlerException ex)
+        {
+            throw new FileHandlerException(Error + "pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG", ex);
+        }
+
+        catch (FileAlreadyExistsException ex)
+        {
+            throw ex;
+        }
+
+        catch (InstantiationException ex)
+        {
+            throw new FileHandlerException(Error + "pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG", ex);
+        }
+        catch (IllegalAccessException ex)
+        {
+            throw new FileHandlerException(Error + "pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG", ex);
+        }
+        catch (ClassNotFoundException ex)
+        {
+            throw new FileHandlerException(Error + "pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG", ex);
+        }
+
+        return doc;
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileAlreadyExistsException.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileAlreadyExistsException.java
new file mode 100755
index 0000000..4429b7e
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileAlreadyExistsException.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index.handlers;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class FileAlreadyExistsException extends Exception
+{
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileHandlerException.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileHandlerException.java
new file mode 100755
index 0000000..920db5e
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/FileHandlerException.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.index.handlers;
+
+/**
+ * File Handler Exception
+ * @author Marco
+ */
+public class FileHandlerException extends Exception 
+{
+
+    /**
+     * File Handler Exception
+     * @param string Message to display
+     * @param e base exception caught
+     */
+    public FileHandlerException(String string, Exception e) 
+    {
+        super(string, e);
+    }
+
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/handler.properties b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/handler.properties
new file mode 100755
index 0000000..6bff634
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/index/handlers/handler.properties
@@ -0,0 +1 @@
+dcm = pt.ua.dicoogle.core.index.LuceneSupport.DICOM.DicomDocumentNG
\ No newline at end of file
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/FileObservable.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/FileObservable.java
new file mode 100755
index 0000000..f2dce34
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/FileObservable.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.observables;
+
+import java.io.Serializable;
+import java.util.Observable;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class FileObservable extends Observable implements Serializable
+{
+    private String fileOrigin;
+    private String fileName;
+    private String filePath = null;
+
+    public FileObservable(String fileOrigin, String fileName)
+    {
+        this.fileOrigin = fileOrigin;
+        this.fileName = fileName;
+    }
+
+    public String getFileName()
+    {
+        return fileName;
+    }
+
+    public String getFileOrigin()
+    {
+        return fileOrigin;
+    }
+
+    public String getFilePath()
+    {
+        return filePath;
+    }
+
+    public boolean isCompleted()
+    {
+        return (this.filePath != null);
+    }
+
+    public void setFilePath(String filePath)
+    {
+        this.filePath = filePath;
+        this.setChanged();
+        this.notifyObservers();
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservable.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservable.java
new file mode 100755
index 0000000..aea23c3
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservable.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.observables;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Observable;
+
+/**
+ * Observable responsible for the notification of user interfaces about any change in the
+ * list of members of the view.
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class ListObservable<type> extends Observable
+{
+    //array of the members of the view.
+    private Collection<type> array;
+
+    /**
+     * Constructor of the class. It does nothing.
+     */
+    public ListObservable()
+    {
+        this.array = Collections.synchronizedCollection(new ArrayList<type>());
+    }
+
+    /**
+     * Setter of the memberlist, it receives a vector and puts all members
+     * in the array.
+     * After that it notifies all observers.
+     * @param members
+     */
+    public synchronized void setArray(Collection<type> vec)
+    {
+        //initialization of the memberlist
+        this.array.clear();
+        this.array.addAll(vec);
+        
+        //notification of the observers.
+        this.setChanged();
+        this.notifyObservers();
+    }
+
+    public synchronized void addAll(Collection list)
+    {
+        this.array.addAll(list);
+        this.setChanged();
+        this.notifyObservers();
+    }
+
+    public synchronized void add(type object)
+    {
+        this.array.add(object);
+        this.setChanged();
+        this.notifyObservers();
+    }
+
+    /**
+     * Getter of copy of the array list of the members
+     * @return the list of the members of the view
+     */
+    public ArrayList getArray()
+    {
+        ArrayList newArray = new ArrayList();
+        newArray.addAll(this.array);
+        return newArray;
+    }
+    public void resetArray()
+    {
+        this.array.clear();
+        //notification of the observers.
+        this.setChanged();
+        this.notifyObservers();
+
+    }
+
+    @Override
+    public String toString()
+    {
+        String string = "[ ";
+        for(type element: array)
+        {
+            string += element.toString() + "  ";
+        }
+        string += "]";
+        return string;
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservableSearch.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservableSearch.java
new file mode 100755
index 0000000..a62bd89
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/ListObservableSearch.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.observables;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * @author bastiao
+ */
+public class ListObservableSearch<type> extends ListObservable
+{
+    
+    public ListObservableSearch()
+    {
+        super();   
+    }
+    
+    private Boolean finish = false;
+    private String queryId = "";
+
+    /**
+     * @return the finish
+     */
+    public Boolean isFinish() {
+        return finish;
+    }
+
+    /**
+     * @param finish the finish to set
+     */
+    public void setFinish(Boolean finish) {
+        
+        this.finish = finish;
+    }
+    
+    @Override
+    public ArrayList getArray()
+    {
+        return super.getArray();
+    }
+
+    /**
+     * @return the queryId
+     */
+    public String getQueryId() {
+        return queryId;
+    }
+
+    /**
+     * @param queryId the queryId to set
+     */
+    public void setQueryId(String queryId) {
+        this.queryId = queryId;
+    }
+    
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/MessageObservable.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/MessageObservable.java
new file mode 100755
index 0000000..a29b113
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/observables/MessageObservable.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.observables;
+
+import java.util.Observable;
+
+/**
+ * Observable responsible for the notification of user interfaces about a message received.
+ * @author Pedro Bento
+ * @author Carlos Ferreira
+ */
+public class MessageObservable<I> extends Observable
+{
+    //The last message received.
+
+    private I Message;
+    private String address = null;
+
+    /**
+     * Constructor that just initialize the message.
+     */
+    public MessageObservable()
+    {
+        this.Message = null;
+        this.address = null;
+    }
+
+    /**
+     * Getter of the message.
+     * @return the last message received.
+     */
+    public I getMessage()
+    {
+        return this.Message;
+    }
+
+    public String getAddress()
+    {
+        return address;
+    }
+
+
+    public I getObject()
+    {
+        return this.Message;
+    }
+
+    /**
+     * Setter of the message and consequent notification of all observers.
+     * @param Message New message of the observer.
+     */
+    public void setMessage(I Message, String address)
+    {
+        this.Message = Message;
+        this.address = address;
+        this.setChanged();
+        this.notifyObservers();
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Builders/MessageBuilder.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Builders/MessageBuilder.java
new file mode 100755
index 0000000..a5fbff6
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Builders/MessageBuilder.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Builders;
+
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageFields;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageType;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageXML;
+import pt.ua.dicoogle.sdk.p2p.Messages.SearchResultFields;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import org.dom4j.Document;
+import org.dom4j.DocumentFactory;
+import org.dom4j.Element;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class MessageBuilder
+{
+    public MessageI buildQueryMessage(String query, Collection<String> extrafields, String pluginName, Integer queryNumber) throws IOException
+    {
+        DocumentFactory dfactory = new DocumentFactory();
+        Document document = dfactory.createDocument("UTF-8");
+
+        /**
+         * Creation of the root element of the document
+         */
+        Element root = document.addElement(MessageFields.MESSAGE);
+
+        Element temp;
+        temp = root.addElement(MessageFields.MESSAGE_TYPE);
+        temp.setText(MessageType.QUERY);
+
+        temp = root.addElement(MessageFields.QUERY_NUMBER);
+
+        temp.setText(queryNumber.toString());
+
+        temp = root.addElement(MessageFields.QUERY);
+        temp.setText(query);
+
+        for (String extrafield : extrafields)
+        {
+            temp = root.addElement(MessageFields.EXTRAFIELD);
+            temp.setText(extrafield);
+        }
+
+        OutputFormat format = new OutputFormat("  ", true, "UTF-8");
+        ByteArrayOutputStream a = new ByteArrayOutputStream();
+
+        XMLWriter output = null;
+        try
+        {
+            output = new XMLWriter(a, format);
+        } catch (UnsupportedEncodingException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        output.write(document);
+
+        output.close();
+
+        //just for tests
+        //System.out.println(a.toString());
+
+        return new MessageXML(a.toByteArray());
+    }
+
+    public MessageI buildQueryResponse(List<SearchResult> results, String queryNumber, String pluginName) throws IOException
+    {
+        DocumentFactory dfactory = new DocumentFactory();
+        Document document = dfactory.createDocument("UTF-8");
+        Element root = document.addElement(MessageFields.MESSAGE);
+        Element temp, temp2, temp3;
+        temp = root.addElement(MessageFields.MESSAGE_TYPE);
+        temp.setText(MessageType.QUERY_RESP);
+
+        temp = root.addElement(MessageFields.QUERY_NUMBER);
+        temp.setText(queryNumber);
+        temp = root.addElement(MessageFields.SEARCH_RESULTS);
+        for (SearchResult result : results)
+        {
+            temp2 = temp.addElement(MessageFields.SEARCH_RESULT);
+
+            temp3 = temp2.addElement(SearchResultFields.FILE_NAME);
+            temp3.setText(result.getURI().toString());
+
+            temp3 = temp2.addElement(SearchResultFields.FILE_HASH);
+            temp3.setText(result.get("filehash").toString());
+            //temp3 = temp2.addElement(SearchResultFields.FILE_PATH);
+            //temp3.setText(result.getPath());
+            temp3 = temp2.addElement(SearchResultFields.FILE_SIZE);
+            temp3.setText(result.get("size").toString());
+
+            temp3 = temp2.addElement(SearchResultFields.EXTRAFIELDS);
+            HashMap<String, Object> extrafields = result.getExtraData();
+            Set<String> keys = extrafields.keySet();
+            for (String key : keys)
+            {
+                temp2 = temp3.addElement(key);
+                /** FIXME: Probably need to replace other fields like \14 ? */
+                temp2.setText(extrafields.get(key).toString().replaceAll("\0", " "));
+            }
+        }
+        OutputFormat format = new OutputFormat("  ", true, "UTF-8");
+        ByteArrayOutputStream a = new ByteArrayOutputStream();
+
+        XMLWriter output = null;
+        try
+        {
+            output = new XMLWriter(a, format);
+        } catch (UnsupportedEncodingException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        output.write(document);
+
+        output.close();
+        return new MessageXML(a.toByteArray());
+    }
+
+    public MessageI buildFileRequest(String filename, String fileHash, String pluginName) throws IOException
+    {
+        DocumentFactory dfactory = new DocumentFactory();
+        Document document = dfactory.createDocument("UTF-8");
+        Element root = document.addElement(MessageFields.MESSAGE);
+        Element temp;
+        temp = root.addElement(MessageFields.MESSAGE_TYPE);
+        temp.setText(MessageType.FILE_REQ);
+        temp = root.addElement(MessageFields.FILE_REQUESTED);
+        Element temp2 = temp.addElement(SearchResultFields.FILE_NAME);
+        temp2.setText(filename);
+        temp2 = temp.addElement(SearchResultFields.FILE_HASH);
+        temp2.setText(fileHash);
+        OutputFormat format = new OutputFormat("  ", true, "UTF-8");
+        ByteArrayOutputStream a = new ByteArrayOutputStream();
+
+        XMLWriter output = null;
+        try
+        {
+            output = new XMLWriter(a, format);
+        } catch (UnsupportedEncodingException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        output.write(document);
+
+        output.close();
+        return new MessageXML(a.toByteArray());
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/FileMessage.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/FileMessage.java
new file mode 100755
index 0000000..6d6de9e
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/FileMessage.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class FileMessage extends ObjMessage<byte[]>
+{
+    private String filename;
+
+    public FileMessage(byte[] obj, String Type, String Filename)
+    {
+        super(obj, Type);
+        this.filename = Filename;
+    }
+
+    public String getFilename()
+    {
+        return filename;
+    }    
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileRequestHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileRequestHandler.java
new file mode 100755
index 0000000..0b8eb03
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileRequestHandler.java
@@ -0,0 +1,158 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+import java.util.Observable;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageFields;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageXML;
+import pt.ua.dicoogle.sdk.p2p.Messages.SearchResultFields;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Observer;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import pt.ua.dicoogle.sdk.NetworkPluginAdapter;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class FileRequestHandler implements MessageHandler, Observer
+{
+
+    private NetworkPluginAdapter NPA;
+
+    public FileRequestHandler(NetworkPluginAdapter NPA)
+    {
+        this.NPA = NPA;
+    }
+
+    public void handleMessage(MessageI message, String address)
+    {
+        if (!MessageXML.class.isInstance(message))
+        {
+            return;
+        }
+        byte[] msg = (byte[]) message.getMessage();
+
+        SAXReader saxReader = new SAXReader();
+
+        Document document = null;
+        try
+        {
+            document = saxReader.read(new ByteArrayInputStream(msg));
+        } catch (DocumentException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        Element root = document.getRootElement();
+        if (root == null)
+        {
+            return;
+        }
+
+        Element tmp = root.element(MessageFields.FILE_REQUESTED);
+        if (tmp == null)
+        {
+            return;
+        }
+        Element temp2 = tmp.element(SearchResultFields.FILE_NAME);
+        String Filename = temp2.getText();
+        temp2 = tmp.element(SearchResultFields.FILE_HASH);
+        String Filehash = temp2.getText();
+
+        //public TaskRequest(int Task, String RequesterPlugin, Map<Integer , Object> Parameters)
+        HashMap<Integer, Object> parameters = new HashMap<Integer, Object>();
+        parameters.put(TaskRequestsConstants.P_QUERY, "FileHash:" + Filehash + " AND FileName:\"" + Filename+"\"");
+        parameters.put(TaskRequestsConstants.P_EXTRAFIELDS, new ArrayList<String>());
+        parameters.put(TaskRequestsConstants.P_REQUESTER_ADDRESS, address);
+
+        TaskRequest task = new TaskRequest(TaskRequestsConstants.T_QUERY_LOCALLY, this.NPA.getName(), parameters);
+        task.addObserver(this);
+        this.NPA.getTaskRequestsList().addTask(task);
+        //System.out.println("handle message do FileRequestHandler....\n The query is: " + "FileHash:" + Filehash + " and FileName:" + Filename);
+
+        //List<SearchResult> sr = IndexEngine.getInstance().search("FileHash:"+Filehash+" and FileName:"+Filename, null);
+        //String filepath = new String(Base64.decodeBase64(tmp.getText().getBytes()));
+
+    }
+
+    /*  public void update(Observable o, Object arg)
+    {
+    if (!TaskRequest.class.isInstance(o))
+    {
+    return;
+    }
+    
+    TaskRequest task = (TaskRequest) o;
+    
+    if (task.hasChanged())
+    {
+    List<SearchResult> sr = (List<SearchResult>) task.getResults().get(TaskRequestsConstants.R_SEARCH_RESULTS);
+    
+    if ((sr == null) || (sr.isEmpty()))
+    {
+    return;
+    }
+    this.NPA.sendFile(sr.get(0).getOrigin(), this.NPA.getName());
+    }
+    }*/
+    public void update(Observable o, Object arg)
+    {
+        //System.out.println("Update do FileRequestHandler.........");
+        if (TaskRequest.class.isInstance(o))
+        {
+            //System.out.println("Update do FileRequestHandler -> 1");
+            TaskRequest tr = (TaskRequest) o;
+            if (tr.getTask() != TaskRequestsConstants.T_QUERY_LOCALLY)
+            {
+                //System.out.println("Update do FileRequestHandler -> 2");
+                return;
+            }
+            //System.out.println("Update do FileRequestHandler -> 3");
+            Map<Integer, Object> parameters = tr.getParameters();
+            Map<Integer, Object> results = tr.getResults();
+            if ((parameters.get(TaskRequestsConstants.P_REQUESTER_ADDRESS) != null) && (results.get(TaskRequestsConstants.R_SEARCH_RESULTS) != null)
+                    && List.class.isInstance(results.get(TaskRequestsConstants.R_SEARCH_RESULTS)))
+            {
+                //System.out.println("Update do FileRequestHandler -> 4");
+                List srList = (List) results.get(TaskRequestsConstants.R_SEARCH_RESULTS);
+                if (srList.isEmpty() || (!SearchResult.class.isInstance(srList.get(0))))
+                {
+                    //System.out.println("The list has " + srList.size() + " elements");
+                    return;
+                }
+                SearchResult sr = (SearchResult) srList.get(0);
+
+                NPA.sendFile(sr.getURI().toString(), (String) parameters.get(TaskRequestsConstants.P_REQUESTER_ADDRESS));
+                //System.out.println("Message Sent?");
+            }
+        }
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileResponseHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileResponseHandler.java
new file mode 100755
index 0000000..e4c6e95
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/FileResponseHandler.java
@@ -0,0 +1,132 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+import java.io.File;
+import java.awt.Desktop;
+import java.util.HashMap;
+import java.util.List;
+import pt.ua.dicoogle.sdk.NetworkPluginAdapter;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.observables.FileObservable;
+import pt.ua.dicoogle.sdk.p2p.Messages.FileMessage;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+
+/**
+ *
+ * @author Carlos Ferreira
+ */
+public class FileResponseHandler implements MessageHandler
+{
+
+    private String DirectoryPath;
+    private NetworkPluginAdapter NPA;
+
+    public FileResponseHandler(String DirectoryPath, NetworkPluginAdapter NPA)
+    {
+        this.NPA = NPA;
+        this.DirectoryPath = DirectoryPath;
+        File directory = new File(this.DirectoryPath);
+
+        //System.out.println(directory.getAbsoluteFile());
+        if (!directory.exists())
+        {
+            directory.mkdir();
+        } else
+        {
+            if (!directory.isDirectory())
+            {
+                //   throw new BadMessage();
+            }
+        }
+    }
+
+    public void handleMessage(MessageI message, String address)
+    {
+        if (!FileMessage.class.isInstance(message))
+        {
+            return;
+        }
+        FileMessage fmessage = (FileMessage) message;
+
+        /**
+         * ATTENTION: the FileMessage sent by the plugin is now only constituted by the filePath...
+         * The plugin is responsible for the storage of the file into the local file system
+         */
+        String filePath = new String(fmessage.getMessage());
+        List<FileObservable> filesRequested = this.NPA.getRequestedFiles();
+        for (FileObservable fo : filesRequested)
+        {
+            if ((fo.getFileOrigin().compareTo(address) == 0) && (fo.getFileName().compareTo(fmessage.getFilename()) == 0))
+            {
+                /**
+                 * Request the local indexing of the new file
+                 */
+                HashMap<Integer, Object> parameters = new HashMap<Integer, Object>();
+                parameters.put(TaskRequestsConstants.P_FILE_PATH, filePath);
+                TaskRequest task = new TaskRequest(TaskRequestsConstants.T_INDEX_FILE, this.NPA.getName(), parameters);
+                this.NPA.getTaskRequestsList().addTask(task);
+
+                /**
+                 * TODO: This must be removed when the GUI is able to deal with the new files and show them
+                 */
+                try
+                {
+                    Desktop.getDesktop().open(new File(filePath.replace('\\', '/')));
+                } catch (Exception e)
+                {
+                    e.printStackTrace();
+                }
+                fo.setFilePath(filePath);
+                break;
+            }
+        }
+
+
+        /*ObjMessage msg = (ObjMessage) message;
+        
+        //File received = (File) msg.getMessage();
+        
+        File newFile = new File(this.DirectoryPath + File.separator + ((FileMessage)message).getFilename() );
+        
+        FileOutputStream fos = null;
+        byte[] bytes = null;
+        bytes = (byte[]) msg.getMessage();
+        try
+        {
+        fos = new FileOutputStream(newFile);
+        } catch (FileNotFoundException ex) {
+        ex.printStackTrace(System.out);
+        }
+        try {
+        fos.write(bytes);
+        } catch (IOException ex) {
+        ex.printStackTrace(System.out);
+        } finally {
+        try {
+        fos.close();
+        } catch (IOException ex) {
+        ex.printStackTrace(System.out);
+        }
+        }
+        IndexEngine.getInstance().index(newFile.getAbsolutePath());
+         */
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MainMessageHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MainMessageHandler.java
new file mode 100755
index 0000000..8de4697
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MainMessageHandler.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+//import pt.ua.dicoogle.p2p.jgroups.sockets.MulticastSocketHandler;
+import pt.ua.dicoogle.sdk.NetworkPluginAdapter;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.observables.ListObservable;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageType;
+
+/**
+ * Class that chooses which message handler will process the message received.
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class MainMessageHandler implements MessageHandler
+{
+    private NetworkPluginAdapter NPA;
+    private ListObservable<SearchResult> results = null;
+
+    public MainMessageHandler(NetworkPluginAdapter NPA)
+    {
+        this.NPA = NPA;
+        results = NPA.getSearchResults();
+    }
+
+    public void handleMessage(MessageI message, String address)
+    {
+        MessageHandler handler = null;
+        if (message.getType().equals(MessageType.QUERY))
+        {
+            if (address.equals(this.NPA.getLocalAddress()))
+            {
+                return;
+            }
+            handler = new QueryHandler(1000, this.NPA);
+        }
+        if (message.getType().equals(MessageType.QUERY_RESP))
+        {
+            handler = new QueryResponseHandler(this.NPA, this.results);
+        }
+
+        if (message.getType().equals(MessageType.FILE_REQ))
+        {
+            handler = new FileRequestHandler(this.NPA);
+        }
+        if (message.getType().equals(MessageType.FILE_RESP))
+        {
+            handler = new FileResponseHandler("received", this.NPA);
+        }
+        handler.handleMessage(message, address);
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MessageHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MessageHandler.java
new file mode 100755
index 0000000..37e28dc
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/MessageHandler.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+
+/**
+ * Interface that must be implemented by all message handlers
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public interface MessageHandler
+{
+    /**
+     * Method that handles with the message received.
+     * @param message received
+     */
+    public void handleMessage(MessageI message, String address);
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryHandler.java
new file mode 100755
index 0000000..53c060b
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryHandler.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Observable;
+import java.util.Observer;
+import org.slf4j.LoggerFactory;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import pt.ua.dicoogle.sdk.NetworkPluginAdapter;
+import pt.ua.dicoogle.sdk.Utils.TaskRequest;
+import pt.ua.dicoogle.sdk.Utils.TaskRequestsConstants;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.p2p.Messages.Builders.MessageBuilder;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageFields;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageXML;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class QueryHandler implements MessageHandler, Observer
+{
+
+    private int maxResultsPerMessage;
+    //private ListObservable<TaskRequest> tasks;
+    private NetworkPluginAdapter plugin;
+
+    public QueryHandler(int maxResultsPerMessage, NetworkPluginAdapter plugin)
+    {
+        this.plugin = plugin;
+        this.maxResultsPerMessage = maxResultsPerMessage;
+    }
+
+    public void handleMessage(MessageI message, String sender)
+    {
+        if (!MessageXML.class.isInstance(message))
+        {
+            return;
+        }
+
+        byte[] msg = (byte[]) message.getMessage();
+
+        SAXReader saxReader = new SAXReader();
+
+        Document document = null;
+        try
+        {
+            document = saxReader.read(new ByteArrayInputStream(msg));
+        } catch (DocumentException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        /**
+         * Reading the message XML, getting the necessary fields.
+         */
+        Element root = document.getRootElement();
+        String query;
+        Element queryNumber = root.element(MessageFields.QUERY_NUMBER);
+        List<String> extra = new ArrayList();
+        Element queryE = root.element(MessageFields.QUERY);
+        /**
+         * If the message has not the query element, then it is an invalid message
+         * ignore it.
+         */
+        if (queryE == null)
+        {
+            return;
+        }
+        query = queryE.getText();
+        List<Element> extrafields = root.elements(MessageFields.EXTRAFIELD);
+        if (extrafields == null)
+        {
+            extrafields = new ArrayList();
+        }
+        for (Element extrafield : extrafields)
+        {
+            extra.add(extrafield.getText());
+        }
+
+        /**
+         * Local search.
+         */
+        Map<Integer, Object> parameters = new HashMap<Integer, Object>();
+        parameters.put(TaskRequestsConstants.P_QUERY, query);
+        parameters.put(TaskRequestsConstants.P_EXTRAFIELDS, extra);
+        parameters.put(TaskRequestsConstants.P_REQUESTER_ADDRESS, sender);
+        parameters.put(TaskRequestsConstants.P_QUERY_NUMBER, queryNumber.getText());
+
+        TaskRequest task = new TaskRequest(TaskRequestsConstants.T_QUERY_LOCALLY,
+                this.plugin.getName(), parameters);
+        task.addObserver(this);
+
+        this.plugin.getTaskRequestsList().addTask(task);
+
+
+        // ArrayList<SearchResult> resultsAll = IndexEngine.getInstance().search(query, extra);
+        //
+    }
+
+    public void update(Observable o, Object arg)
+    {
+
+        if (!TaskRequest.class.isInstance(o))
+        {
+            return;
+        }
+
+        TaskRequest task = (TaskRequest) o;
+
+
+        Map<Integer, Object> res = task.getResults();
+        Object SR = res.get(TaskRequestsConstants.R_SEARCH_RESULTS);
+        if ((SR == null) || (!ArrayList.class.isInstance(SR)))
+        {
+            return;
+        }
+
+        ArrayList<SearchResult> resultsAll = (ArrayList<SearchResult>) SR;
+        List<SearchResult> results;
+        /**
+         * Build of the response for the query
+         */
+        MessageBuilder builder = new MessageBuilder();
+        MessageI newMessage = null;
+        for (int i = 0; i < resultsAll.size(); i += maxResultsPerMessage)
+        {
+            int size = maxResultsPerMessage;
+            if (i + maxResultsPerMessage > resultsAll.size())
+            {
+                size = resultsAll.size() - i;
+            }
+
+            results = resultsAll.subList(i, i + size);
+            try
+            {
+                newMessage = builder.buildQueryResponse(results, (String) task.getParameters().get(TaskRequestsConstants.P_QUERY_NUMBER), this.plugin.getName());
+            } catch (IOException ex)
+            {
+                LoggerFactory.getLogger(QueryHandler.class).error(ex.getMessage(), ex);
+            }
+
+            /**
+             * Sending the response
+             */
+            if (newMessage != null)
+            {
+                
+                this.plugin.send(newMessage, (String) task.getParameters().get(TaskRequestsConstants.P_REQUESTER_ADDRESS));
+            }
+        }
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryResponseHandler.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryResponseHandler.java
new file mode 100755
index 0000000..57b3c02
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/Handlers/QueryResponseHandler.java
@@ -0,0 +1,170 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages.Handlers;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+import pt.ua.dicoogle.sdk.NetworkPluginAdapter;
+import pt.ua.dicoogle.sdk.observables.ListObservable;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageFields;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageI;
+import pt.ua.dicoogle.sdk.p2p.Messages.MessageXML;
+import pt.ua.dicoogle.sdk.p2p.Messages.SearchResultFields;
+import pt.ua.dicoogle.sdk.Utils.QueryNumber;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class QueryResponseHandler implements MessageHandler
+{
+
+    private NetworkPluginAdapter NPA;
+    private ListObservable<SearchResult> results;
+
+    public QueryResponseHandler(NetworkPluginAdapter NPA, ListObservable<SearchResult> results)
+    {
+        this.NPA = NPA;
+        this.results = results;
+    }
+
+    public void handleMessage(MessageI message, String sender)
+    {
+        if (!MessageXML.class.isInstance(message))
+        {
+            return;
+        }
+
+        MessageXML msg = (MessageXML) message;
+
+        /**
+         * leitura do pacote.
+         */
+        byte[] xml = msg.getMessage();
+        SAXReader saxReader = new SAXReader();
+
+        Document document = null;
+        try
+        {
+            document = saxReader.read(new ByteArrayInputStream(xml));
+        } catch (DocumentException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+
+        Element root = document.getRootElement();
+
+        /**
+         * Verification of the validity of the message
+         */
+        if (!root.getName().equals(MessageFields.MESSAGE))
+        {
+            return;
+        }
+
+        Element tmp = root.element(MessageFields.QUERY_NUMBER);
+        if (tmp == null)
+        {
+            return;
+        }
+
+        Integer queryNumber = null;
+        try
+        {
+            queryNumber = Integer.parseInt(tmp.getText());
+        } catch (Exception ex)
+        {
+            return;
+        }
+
+        /**
+         * if the queryNumber is not the most recent query's number, then ignore the message
+         * It is the response for a search deprecated.
+         * This will be checked again, nevertheless here it is checked to save time 
+         * with avoidable XML processing in case of the deprecation of the message received
+         */
+        if (queryNumber != QueryNumber.getInstance().getQueryNumber())
+        {
+            return;
+        }
+
+        tmp = root.element(MessageFields.SEARCH_RESULTS);
+        List<Element> Results = tmp.elements(MessageFields.SEARCH_RESULT);
+        List<SearchResult> res = new ArrayList<SearchResult>();
+        Element tmp2;
+        for (Element result : Results)
+        {
+            String Filename = null, FileHash = null, FileSize = null;
+            tmp2 = result.element(SearchResultFields.FILE_NAME);
+            if (tmp2 == null)
+            {
+                return;
+            }
+            Filename = tmp2.getText();
+
+            tmp2 = result.element(SearchResultFields.FILE_HASH);
+            if (tmp2 == null)
+            {
+                return;
+            }
+            FileHash = tmp2.getText();
+
+            tmp2 = result.element(SearchResultFields.FILE_SIZE);
+            if (tmp2 == null)
+            {
+                return;
+            }
+            FileSize = tmp2.getText();
+
+            tmp2 = result.element(SearchResultFields.EXTRAFIELDS);
+            if (tmp2 == null)
+            {
+                return;
+            }
+            List<Element> fields = tmp2.elements();
+            HashMap<String, Object> Extrafields = new HashMap();
+            for (Element field : fields)
+            {
+                Extrafields.put(field.getName(), field.getText());
+            }
+            //res.add(new SearchResult(FileHash, Filename, sender, FileSize, Extrafields, this.NPA.getName()));
+            throw new UnsupportedOperationException("FIX THIS!!!: qwe123");
+        }
+        synchronized (this.results) // monitor to queryNumber
+        {
+            if (queryNumber != QueryNumber.getInstance().getQueryNumber())
+            {
+                //System.out.println("different QueryNumber");
+                return;
+            }
+            this.results.resetArray();
+            this.results.addAll(res);
+            //System.out.println(this.results.getArray().size() + "results added to the observable");
+        }
+
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageFields.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageFields.java
new file mode 100755
index 0000000..059e0df
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageFields.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class MessageFields
+{
+    /**
+     * Root element of every xml messages
+     */
+    public static final String MESSAGE = "Message";
+
+    /**
+     * Definition of the message type
+     */
+    public static final String MESSAGE_TYPE = "MessageType";
+    /**
+     * The number of the query
+     */
+    public static final String QUERY_NUMBER = "QueryNumber";
+    /**
+     * The field where the query value is declared
+     */
+    public static final String QUERY = "Query";
+    /**
+     * The list of search results
+     */
+    public static final String SEARCH_RESULTS = "SearchResults";
+    public static final String EXTRAFIELD = "Extrafield";
+
+    /**
+     * One result of the search.
+     */
+    public static final String SEARCH_RESULT = "SearchResult";
+
+    public static final String FILE_REQUESTED = "FileRequested";
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageI.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageI.java
new file mode 100755
index 0000000..92f254e
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageI.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+import java.io.Serializable;
+
+/**
+ * All messages shall implement this interface
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public interface MessageI<I> extends Serializable
+{
+    public I getMessage();
+    public String getType();
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageType.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageType.java
new file mode 100755
index 0000000..78dd1ef
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageType.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+/**
+ * @author Pedro Bento
+ * @author Carlos Ferreira
+ */
+public class MessageType
+{
+    public static final String QUERY = "Query";
+    public static final String QUERY_RESP = "Query Response";
+    public static final String FILE_REQ = "File Request";
+    public static final String FILE_RESP = "File Response";
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageXML.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageXML.java
new file mode 100755
index 0000000..7a2258b
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/MessageXML.java
@@ -0,0 +1,68 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+import java.io.ByteArrayInputStream;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class MessageXML implements MessageI<byte[]>
+{
+    private String Message;
+
+    public MessageXML(byte[] message)
+    {
+        this.Message = new String(message);
+    }
+
+    public String getType()
+    {
+        SAXReader saxReader = new SAXReader();
+        ByteArrayInputStream input = new ByteArrayInputStream(Message.getBytes());
+        Document document = null;
+        try
+        {
+            document = saxReader.read(input);
+        } catch (DocumentException ex)
+        {
+            ex.printStackTrace(System.out);
+        }
+        Element root = document.getRootElement();
+        Element tmp = root.element(MessageFields.MESSAGE_TYPE);
+        return tmp.getText();
+    }
+
+    public byte[] getMessage()
+    {
+        return this.Message.getBytes();
+    }
+
+    @Override
+    public String toString()
+    {
+        return this.Message;
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/ObjMessage.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/ObjMessage.java
new file mode 100755
index 0000000..a65eff7
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/ObjMessage.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+/**
+ * Object to be sent
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class ObjMessage<type> implements MessageI<type>
+{
+    private type message;
+    private String Type;
+    
+    public ObjMessage(type message, String Type)
+    {
+        this.message = message;
+        this.Type = Type;
+    }
+
+    public type getMessage()
+    {
+        return this.message;
+    }
+
+    public String getType()
+    {
+        return this.Type;
+    }
+}
diff --git a/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/SearchResultFields.java b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/SearchResultFields.java
new file mode 100755
index 0000000..7826244
--- /dev/null
+++ b/sdk-ext/src/main/java/pt/ua/dicoogle/sdk/p2p/Messages/SearchResultFields.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk-ext.
+ *
+ * Dicoogle/dicoogle-sdk-ext is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk-ext is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.p2p.Messages;
+
+/**
+ *
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ */
+public class SearchResultFields
+{
+    public static final String FILE_NAME = "FileName";
+    public static final String FILE_HASH = "FileHash";
+    public static final String FILE_PATH = "FilePath";
+    public static final String FILE_SIZE = "FileSize";
+    public static final String EXTRAFIELDS = "Extrafields";
+}
diff --git a/sdk/.gitignore b/sdk/.gitignore
new file mode 100644
index 0000000..71018fd
--- /dev/null
+++ b/sdk/.gitignore
@@ -0,0 +1,2 @@
+/target
+/dependency-reduced-pom.xml
diff --git a/sdk/pom.xml b/sdk/pom.xml
new file mode 100644
index 0000000..f1e87af
--- /dev/null
+++ b/sdk/pom.xml
@@ -0,0 +1,208 @@
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dicoogle-sdk</artifactId>
+    <packaging>jar</packaging>
+    <name>dicoogle-sdk</name>
+    <url>http://www.dicoogle.com</url>
+
+    <parent>
+        <groupId>pt.ua.ieeta</groupId>
+        <artifactId>dicoogle-all</artifactId>
+        <version>2.5.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <repositories>
+
+        <repository>
+            <id>mavencentral</id>
+            <url>http://repo1.maven.org/maven2/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>dcm4che</id>
+            <url>http://www.dcm4che.org/maven2/</url>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>maven-restlet</id>
+            <name>Public online Restlet repository</name>
+            <url>http://maven.restlet.org</url>
+        </repository>
+    </repositories>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>2.3</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>**/*.SF</exclude>
+                                        <exclude>**/*.DSA</exclude>
+                                        <exclude>**/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>2.3.2</version>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <source>1.7</source>
+                    <target>1.7</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>2.4.3</version>
+                <configuration>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.mycila</groupId>
+                <artifactId>license-maven-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <header>../short-license.txt</header>
+                    <includes>
+                        <include>**/*.java</include>
+                    </includes>
+                    <excludes>
+                        <exclude>**/package-info.java</exclude>
+                    </excludes>
+
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.8.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-configuration</groupId>
+            <artifactId>commons-configuration</artifactId>
+            <version>1.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>dcm4che</groupId>
+            <artifactId>dcm4che-core</artifactId>
+            <version>${dcm4che.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>dcm4che</groupId>
+            <artifactId>dcm4che-net</artifactId>
+            <version>${dcm4che.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>fakepath</groupId>
+            <artifactId>jspf.core</artifactId>
+            <version>1.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.restlet.jse</groupId>
+            <artifactId>org.restlet</artifactId>
+            <version>${restlet.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.restlet.jse</groupId>
+            <artifactId>org.restlet.ext.json</artifactId>
+            <version>${restlet.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.swinglabs</groupId>
+            <artifactId>swing-layout</artifactId>
+            <version>1.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${jetty.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+    </dependencies>
+    <distributionManagement>
+
+        <!-- Versioned releases are published to the releases repository -->
+        <repository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi</url>
+        </repository>
+
+
+        <!-- Snapshot releases are published to the snapshots repository -->
+        <snapshotRepository>
+            <id>mi</id>
+            <url>http://bioinformatics.ua.pt/maven/content/repositories/mi-snapshots</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+
+</project>
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/DicooglePlugin.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/DicooglePlugin.java
new file mode 100755
index 0000000..b157299
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/DicooglePlugin.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import pt.ua.dicoogle.sdk.settings.ConfigurationHolder;
+import net.xeoh.plugins.base.Plugin;
+
+/** Class interface representing a generic plugin.
+ * <p>
+ * These plugins can have an initialization process, and can be enabled or disabled by the system.
+ * Furthermore, every plugin must have a name, so that Dicoogle can address it and control it. No further
+ * assumptions are made here regarding functionality. Any other more specific functionality must be defined
+ * as a class inheriting from this one.</p>
+ * 
+ * @author Frederico Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface DicooglePlugin extends Plugin {
+    
+    /**
+     * Obtains the unique name of plugin. 
+     * A plugin must have a name to serve as an ID, and this is the method from where it is retrieved. This
+     * name must never change.
+     * 
+     * @return the name of the plugin
+     */
+    public abstract String getName();
+    
+    /**
+     * Issues the plugin to become enabled. It is expected that an enabled plugin, once configured, is ready
+     * to perform its main tasks.
+     * 
+     * @return whether the plugin was successfully enabled
+     */
+    public abstract boolean enable();
+    
+    /**
+     * Issues the plugin to become disabled. When called, the plugin is responsible
+     * for stopping all services that the plugin is running. 
+     * @return whether the plugin was successfully disabled
+     */
+    public abstract boolean disable();
+    
+    
+    /**
+     * Verifies if the plugin is enabled.
+     *
+     * @return whether the plugin is enabled
+     */
+    public abstract boolean isEnabled();
+
+    /** Sets the settings of this plugin.
+     * This method lets the plugin receive its settings from the core Dicoogle system.
+     * 
+     * @param settings the parameters that will be used by the plugin
+     */
+    public abstract void setSettings(ConfigurationHolder settings);
+    
+    /**
+     * Obtains access to the settings of the plugin.
+     * @return the plugin's settings
+     */
+    public abstract ConfigurationHolder getSettings();    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/GraphicalInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/GraphicalInterface.java
new file mode 100755
index 0000000..79c3c89
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/GraphicalInterface.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.util.ArrayList;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+
+/**
+ * This interface exposes the GUI of Dicoogle in a controlled way.
+ * Plugins implementing this interface should override this methods
+ * If some of the functionality is not required (for instance, if there is
+ * no need for a top icon), the respective methods overloads should return null
+ *
+ * @author Frederico Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * 
+ * @deprecated The remote Swing-based GUI is outdated and will no longer be supported.
+ */
+ at Deprecated
+public interface GraphicalInterface extends DicooglePlugin
+{
+    public ArrayList<JMenuItem> getRightButtonItems();
+    public ArrayList<JPanel> getTopIcons();
+    public ArrayList<JPanel> getTabPanels();
+    public ArrayList<JMenuItem> getMenuItems();
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/IndexerInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/IndexerInterface.java
new file mode 100755
index 0000000..6ec3a8f
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/IndexerInterface.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.net.URI;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * Index Interface Plugin. Indexers analyze documents for performing queries. They may index
+ * documents by DICOM metadata for instance, but other document processing procedures may be involved.
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Frederico Valente <fmvalente at ua.pt>
+ */
+public interface IndexerInterface extends DicooglePlugin {
+
+    /**
+     * Indexes the file path to the database. Indexation procedures are asynchronous, and will return
+     * immediately after the call. The outcome is a report that can be retrieved from the given task
+     * as a future.
+     *
+     * @param file directory or file to index
+     * @return a representation of the asynchronous indexation task
+     */
+    public Task<Report> index(StorageInputStream file, Object ... parameters);
+
+    /**
+     * Indexes multiple file paths to the database. Indexation procedures are asynchronous, and will return
+     * immediately after the call. The outcomes are aggregated into a single report and can be retrieved from
+     * the given task as a future.
+     *
+     * @param files a collection of directories and/or files to index
+     * @return a representation of the asynchronous indexation task
+     */
+    public Task<Report> index(Iterable<StorageInputStream> files, Object ... parameters);
+
+    
+    /**
+     * Checks whether the file in the given path can be indexed by this indexer. The indexer should verify if
+     * the file holds compatible content (e.g. a DICOM file). If this method returns false, the file will not
+     * be indexed.
+     *
+     * @param path a URI to the file to check
+     * @return whether the indexer can handle the file at the given path
+     */
+    public boolean handles(URI path);    
+    
+    /**
+     * Removes the indexed file at the given path from the database.
+     * 
+     * @param path the URI of the document
+     * @return whether it was successfully deleted from the database
+     */
+    public boolean unindex(URI path);
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/JettyPluginInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/JettyPluginInterface.java
new file mode 100644
index 0000000..5a5673d
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/JettyPluginInterface.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import org.eclipse.jetty.server.handler.HandlerList;
+
+/** Plugin interface for allowing developers to make Jetty-based pluggable web services for Dicoogle.
+ *
+ * @author Frederico Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface JettyPluginInterface extends DicooglePlugin {
+    
+    /** Obtains the list of handlers to be attached to Dicoogle's web server resource hierarchy.
+     * 
+     * @return a list of servlet handlers to be attached
+     */
+    HandlerList getJettyHandlers();
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginBase.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginBase.java
new file mode 100644
index 0000000..955bd3d
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginBase.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import pt.ua.dicoogle.sdk.settings.ConfigurationHolder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.restlet.resource.ServerResource;
+
+import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface;
+import pt.ua.dicoogle.sdk.core.PlatformCommunicatorInterface;
+
+/**
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Luís S. Ribeiro
+ */
+public abstract class PluginBase implements PluginSet, PlatformCommunicatorInterface{
+    
+	protected List<IndexerInterface> indexPlugins = new ArrayList<>();
+    protected List<GraphicalInterface> graphicPlugins = new ArrayList<>();
+    protected List<QueryInterface> queryPlugins = new ArrayList<>();
+    protected List<JettyPluginInterface> jettyPlugins = new ArrayList<>();
+    //protected List<StorageInterface> storagePlugins = new ArrayList<>();
+    protected List<StorageInterface> storagePlugins = new LinkedList<>();
+    
+    protected List<ServerResource> services = new ArrayList<>();
+    protected ConfigurationHolder settings = null;
+    
+    protected DicooglePlatformInterface platform;
+    
+    @Override
+    public List<IndexerInterface> getIndexPlugins() {
+        return indexPlugins;
+    }
+
+ 
+    @Override
+    public List<GraphicalInterface> getGraphicalPlugins() {
+        return graphicPlugins;
+    }
+
+
+    @Override
+    public List<QueryInterface> getQueryPlugins() {
+        return queryPlugins;
+    }
+
+   
+    @Override
+    public List<ServerResource> getRestPlugins() {
+        return services;
+    }
+    
+    @Override
+    public List<JettyPluginInterface> getJettyPlugins(){
+        return jettyPlugins;
+    }
+      
+    @Override
+    public abstract String getName();
+    
+    @Override
+    public ConfigurationHolder getSettings(){
+        return settings;
+    }
+    
+    @Override
+    public void setSettings(ConfigurationHolder xmlSettings){
+        settings = xmlSettings;
+    }
+    
+    @Override
+    public void shutdown(){
+        
+        //settings.save();
+    }
+
+    @Override
+    public Collection<StorageInterface> getStoragePlugins() 
+    {
+        return storagePlugins;
+    }
+    
+    @Override
+	public void setPlatformProxy(DicooglePlatformInterface core) {
+		this.platform = core;
+	}
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginSet.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginSet.java
new file mode 100644
index 0000000..00c8abb
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/PluginSet.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.util.Collection;
+
+import net.xeoh.plugins.base.Plugin;
+
+import org.restlet.resource.ServerResource;
+
+import pt.ua.dicoogle.sdk.settings.ConfigurationHolder;
+
+/**
+ * This is the class responsible for creating a Dicoolge plugin.
+ * The developer may use this interface in order to manage and expose the implemented plugins. One instance
+ * of each installed plugin set is created by injecting it as a {@link PluginImplementation}. All instances
+ * are expected to be thread safe. It is highly recommended that provided collections are immutable, and
+ * that no modifications are performed in getter methods.
+ * 
+ * @author psytek
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface PluginSet extends Plugin {
+    
+    /**
+     * Gets the indexer plugins enclosed in this plugin set.
+     * This collection must be immutable.
+     * @return IndexPluginInterface returns a list of active index plugins
+     * @see IndexerInterface
+     */
+    public Collection<IndexerInterface> getIndexPlugins();
+
+    /**
+     * Gets the graphical plugins enclosed in this plugin set.
+     * This collection must be immutable.
+     * @return 
+     * @deprecated the Swing-based remote user interface is deprecated
+     */
+    public Collection<GraphicalInterface> getGraphicalPlugins();
+
+    /**
+     * Gets the query plugins enclosed in this plugin set.
+     * This collection must be immutable.
+     * @return a collection of query plugins
+     * @see QueryInterface
+     */
+    public Collection<QueryInterface> getQueryPlugins();
+    
+    /**
+     * Gets the storage plugins enclosed in this plugin set.
+     * This collection must be immutable.
+     * @return Collection holding the StoragePlugins of this PluginSet
+     */
+    public Collection<StorageInterface> getStoragePlugins();
+    
+    /**
+     * Obtains a collection of access to the RESTful resources. These plugins will be installed to
+     * the web service hierarchy according to a name defined by the object's {@code toString()} method.
+     * This collection must be immutable.
+     * @return a collection of Restlet-based server resources, implementing {@code toString()}
+     * to provide the resource name
+     */
+    public Collection<ServerResource> getRestPlugins();
+    
+    /**
+     * Obtains a collection of Jetty plugins, so as to implement web services via Dicoogle.
+     * This collection must be immutable.
+     * @return a collection of Jetty plugins to the core application
+     * @see JettyPluginInterface
+     */
+    public Collection<JettyPluginInterface> getJettyPlugins();
+    
+    /**
+     * Gets the plugin's name. This name will be used for identifying index/query/storage providers,
+     * and should be unique among the total plugin sets installed.
+     * @return the name of the plugin, never changes
+     */
+    public String getName();
+    
+    /**
+     * Defines the plugin's settings. This method will be called once after the plugin set was instantiated
+     * with plugin-scoped settings. Dicoogle users can modify these settings by accessing the XML file with
+     * the same name in the "Settings" folder. Developers may define such settings programmatically from the
+     * plugin itself.
+     * @param xmlSettings an XML-based configuration holder
+     */
+    public void setSettings(ConfigurationHolder xmlSettings);
+    
+    /**
+     * Retrieves the plugin's settings.
+     * @return an XML-based configuration holder
+     */
+    public ConfigurationHolder getSettings();
+
+    /**
+     * Signals a plugin to stop. Upon an invocation of this method, the plugin may clean allocated resources
+     * and save state if required.
+     */
+    public void shutdown();
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/QueryInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/QueryInterface.java
new file mode 100644
index 0000000..a94ac82
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/QueryInterface.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ * Query Interface Plugin. Query plugins provide a means of handling queries and obtaining search results.
+ * They will usually rely on indices created by an indexer plugin.
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author fmvalente
+ */
+public interface QueryInterface extends DicooglePlugin 
+{
+    /**
+     * Performs a search on the database.
+     * 
+     * The consumer of the results would either request an iterator or use a for-each loop. The underlying
+     * iterator implementation can be redefined to wait for more results at the caller.
+     *
+     * @param query a string describing the query. The underlying plugin is currently free to follow any
+     * query format, but only those based on Lucene with work with the search user interface.
+     * @param parameters A variable list of parameters of the query. The plugin can use them to establish
+     * their own API's, which may require more complex data structures (e.g. images).
+     * 
+     * @return the results of the query as a (possibly lazy) iterable
+     */
+    public Iterable<SearchResult> query(String query, Object ... parameters);
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInputStream.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInputStream.java
new file mode 100644
index 0000000..56d0e13
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInputStream.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+/** An entity containing the means to read a file or a blob via Dicoogle.
+ * Instances of this class are returned when asking for listings of resources, and do not open an input
+ * stream automatically, thus why the class does not extend {@code InputStream}.
+ * 
+ * @author Frederico Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface StorageInputStream {
+    /** Obtains the file's path.
+     * 
+     * @return the URI path of the file
+     */
+    public abstract URI getURI();
+    
+    /** Obtains a new input stream for reading the file.
+     * 
+     * @return a new input stream
+     * @throws IOException if an I/O error occurs
+     */
+    public abstract InputStream getInputStream() throws IOException;
+    
+    /** Obtains the file's size.
+     * 
+     * @return the storage element's size in byte
+     * @throws IOException if an I/O error occurs
+     */
+    public abstract long getSize() throws IOException;
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInterface.java
new file mode 100644
index 0000000..2ef25e9
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/StorageInterface.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk;
+
+import java.io.IOException;
+import java.net.URI;
+import org.dcm4che2.data.DicomObject;
+import org.dcm4che2.io.DicomInputStream;
+
+/** Storage plugin interface. These types of plugins provide an abstraction to reading and writing from
+ * files or data blobs.
+ * 
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Frederico Valente
+ */
+public interface StorageInterface extends DicooglePlugin {    
+    
+    /**
+     * Gets the scheme URI of this storage plugin.
+     *
+     * @see URI
+     * @return a string denoting the scheme that this plugin associates to
+     */
+    public String getScheme();
+    
+    /**
+     * Checks whether the file in the given path can be handled by this storage plugin.
+     *
+     * @param location a URI containing a scheme to be verified
+     * @return true if this storage plugin is in charge of URIs in the given form 
+     */
+    public boolean handles(URI location);
+    
+    /**
+     * Provides a means of iteration over existing objects at a specified location.
+     * This method is particularly nice for use in for-each loops.
+     * The provided scheme is not relevant at this point, but the developer must avoid calling this method
+     * with a path of a different schema.
+     * 
+     * <pre>for(StorageInputStream dicomObj : storagePlugin.at("file://dataset/")){
+     *      System.err.println(dicomObj.getURI());
+     * }</pre>
+     * 
+     * @param location the location to read
+     * @param parameters a variable list of extra parameters for the retrieve
+     * @return an iterable of storage input streams
+     * @see StorageInputStream
+     */
+    public Iterable<StorageInputStream> at(URI location, Object ... parameters);
+    
+    /**
+     * Stores a DICOM object into the storage.
+     *
+     * @param dicomObject Object to be Stored
+     * @param parameters a variable list of extra parameters for the retrieve
+     * @return The URI of the previously stored Object.
+     */
+    public URI store(DicomObject dicomObject, Object ... parameters);
+
+    /**
+     * Stores a new element into the storage.
+     *
+     * @param inputStream an input stream with the contents to be stored
+     * @param parameters a variable list of extra parameters for the retrieve
+     * @return the URI of the stored data
+     * @throws IOException if an I/O error occurs
+     */
+    public URI store(DicomInputStream inputStream, Object ... parameters) throws IOException;
+    
+    /** Removes an element at the given URI.
+     * 
+     * @param location the URI of the stored data
+     */
+    public void remove(URI location);
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/core/DicooglePlatformInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/DicooglePlatformInterface.java
new file mode 100644
index 0000000..878c0a6
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/DicooglePlatformInterface.java
@@ -0,0 +1,189 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.core;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+
+import pt.ua.dicoogle.sdk.IndexerInterface;
+import pt.ua.dicoogle.sdk.QueryInterface;
+import pt.ua.dicoogle.sdk.StorageInputStream;
+import pt.ua.dicoogle.sdk.StorageInterface;
+import pt.ua.dicoogle.sdk.datastructs.Report;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * Interface for accessing external functionalities of the platform, including other plugins' interfaces.
+ * <p>
+ * For instance, if a graphical plugin needs to query, it will able to access query providers
+ * with this platform. </p>
+ * 
+ * @author: Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Carlos Ferreira
+ * @author Frederico Valente
+ * @see QueryInterface
+ * @see IndexerInterface
+ * @see StorageInterface
+ */
+public interface DicooglePlatformInterface {
+    
+    /**
+     * Gets an installed indexer plugin by name.
+     * @param name the name of the plugin 
+     * @return the plugin that implements this interface
+     */
+    public IndexerInterface requestIndexPlugin(String name);
+    
+    /**
+     * Gets an installed query plugin by name.
+     * @param name the name of the plugin 
+     * @return the plugin that implements this interface
+     */
+    public QueryInterface requestQueryPlugin(String name);
+    
+    /**
+     * Obtains a collection of all active index plugins.
+     * @return an unmodifiable collection of active instances of {@link IndexerInterface}
+     */
+    public Collection<IndexerInterface> getAllIndexPlugins();
+    
+    /**
+     * Obtains a collection of all active query plugins.
+     * @return an unmodifiable collection of active instances of {@link QueryInterface}
+     */
+    public Collection<QueryInterface> getAllQueryPlugins();
+    
+    /** Obtains the storage interface for handling storage of the given scheme.
+     * 
+     * @param scheme the storage scheme
+     * @return the storage interface capable of handling that content, or {@code null} if no storage plugin
+     * installed can.
+     */
+    public StorageInterface getStoragePluginForSchema(String scheme);
+    
+    /** Obtains the storage interface for handling content in the given location.
+     * 
+     * @param location the storage location to check
+     * @return the storage interface capable of handling that content, or {@code null} if no storage plugin
+     * installed can
+     */
+    public StorageInterface getStorageForSchema(URI location);
+    
+    /** Quickly obtains all storage elements at the given location.
+     * 
+     * @param location the location to retrieve
+     * @param args a variable list of extra parameters for the retrieve
+     * @return an iterable of storage input streams
+     */
+    public Iterable<StorageInputStream> resolveURI(URI location, Object ...args);
+    
+    /** Obtains all installed storage plugins.
+     * 
+     * @param onlyEnabled whether only enabled plugins should be retrieved (all are retrieved if {@code false})
+     * @return a collection of storage plugin interfaces
+     */
+    public Collection<StorageInterface> getStoragePlugins(boolean onlyEnabled);
+
+    /** Obtains the storage interface for handling storage of the given scheme.
+     * Same as {@link #getStoragePluginForSchema(java.lang.String)}.
+     * 
+     * @param scheme the storage scheme
+     * @return the storage interface capable of handling that content, or {@code null} if no storage plugin
+     * installed can
+     */
+	public StorageInterface getStorageForSchema(String scheme);
+
+    /** Obtains all installed query plugins.
+     * 
+     * @param onlyEnabled whether only enabled plugins should be retrieved (all are retrieved if {@code false})
+     * @return a collection of query plugin interfaces
+     */
+	public Collection<QueryInterface> getQueryPlugins(boolean onlyEnabled);
+
+    /** Gets the names of all query providers.
+     * 
+     * @param enabled whether only enabled plugins should be retrieved (all are retrieved if {@code false})
+     * @return a collection of unique query provider names
+     */
+	public List<String> getQueryProvidersName(boolean enabled);
+
+    /** Gets the query provider with the given name.
+     * 
+     * @param name the unique name of the provider
+     * @param onlyEnabled whether only enabled plugins should be retrieved (all are retrieved if {@code false})
+     * @return a collection of unique query provider names
+     */
+	public QueryInterface getQueryProviderByName(String name,
+			boolean onlyEnabled);
+
+    /**
+     * Easily performs a query over all query providers. This operation is asynchronous and returns immediately.
+     * @param holder a query task holder containing callback methods
+     * @param query a string describing the query
+     * @param parameters a variable list of extra parameters for the query
+     * @return a join query task
+     */
+	public JointQueryTask queryAll(JointQueryTask holder, String query,
+			Object... parameters) ;
+
+    /** Easily performs a query over a specific provider. This operation is asynchronous and returns immediately.
+     * 
+     * @param querySource the name of the query provider to issue
+     * @param query a string describing the query
+     * @param parameters a variable list of extra parameters for the query
+     * @return an asynchronous task containing the results
+     */
+	public Task<Iterable<SearchResult>> query(String querySource, String query,
+			Object... parameters);
+
+    /** Easily performs a query over multiple providers. This operation is asynchronous and returns immediately.
+     * 
+     * @param holder a query task holder containing callback methods
+     * @param querySources a list of names of query providers to issue
+     * @param query a string describing the query
+     * @param parameters a variable list of extra parameters for the query
+     * @return an asynchronous task containing the results
+     */
+	public JointQueryTask query(JointQueryTask holder,
+			List<String> querySources, String query, Object... parameters);
+
+    /** Easily performs an indexation procedure over all active indexers. This operation is asynchronous
+     * and returns immediately.
+     * 
+     * @param path the path to index
+     * @return a list of asynchronous tasks, one for each provider
+     */
+	public List<Task<Report>> index(URI path);
+
+    /** Easily performs an indexation procedure over all active indexers. This operation is synchronous
+     * and will wait until all providers have finished indexing.
+     * 
+     * @param path the path to index
+     * @return a list of reports, one for each provider
+     */
+	public List<Report> indexBlocking(URI path);
+    
+    /** Obtain access to the server's settings.
+     * @return an object for read-only access to the settings
+     */
+    public ServerSettingsReader getSettings();
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/core/PlatformCommunicatorInterface.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/PlatformCommunicatorInterface.java
new file mode 100644
index 0000000..fd57c8f
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/PlatformCommunicatorInterface.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.core;
+
+/**
+ * Plugin interface to communicate with core and other external plugins (loaded)
+ *
+ * 
+ * When a plugin is loaded, if inherits from this interface,
+ * the loader will call this method with a proxy to the core.
+ * It is up to the plugin maintainer to store that proxy, and use it.
+ * 
+ * @author Fredeiro Valente
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @see DicooglePlatformInterface
+ */
+public interface PlatformCommunicatorInterface 
+{
+    void setPlatformProxy(DicooglePlatformInterface core);
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/core/ServerSettingsReader.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/ServerSettingsReader.java
new file mode 100644
index 0000000..45f1f6d
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/ServerSettingsReader.java
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.sdk.core;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import pt.ua.dicoogle.sdk.datastructs.MoveDestination;
+
+/** A read-only interface for accessing server settings.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public interface ServerSettingsReader {
+
+    public WebSettingsReader getWeb();
+    
+    public String getAE();
+    
+    public int getAcceptTimeout();
+    
+    public String getAccessListFileName();
+    
+    public boolean getAutoStartPlugin(String name);
+
+    public ConcurrentMap<String,Boolean> getAutoStartPluginsSettings();
+    
+    public String[] getCAET();
+    
+    public int getConnectionTimeout();
+    
+    public int getDIMSERspTimeout();
+    
+    public String getDeviceDescription();
+    
+    public String getDicoogleDir();
+    
+    public Set<String> getExtensionsAllowed();
+    
+    public boolean getFullContentIndex();
+    
+    public String getID();
+    
+    public int getIdleTimeout();
+    
+    public String getIndexer();
+    
+    public String getNodeName();
+    
+    public boolean isNodeNameDefined();
+    
+    public String getNetworkInterfaceName();
+    
+    public int getIndexerEffort();
+    
+    public boolean isEncryptUsersFile();
+    
+    public boolean isIndexZIPFiles();
+    
+    public boolean isMonitorWatcher();
+    
+    public boolean isIndexAnonymous();
+    
+    public boolean isGzipStorage();
+    
+    public boolean getPermitAllAETitles();
+    
+    public String getPath();
+    
+    public int getStoragePort();
+    
+    public boolean getSaveThumbnails();
+    
+    public String getThumbnailsMatrix();
+    
+    public int getWlsPort();
+    
+    public int getRspDelay();
+    
+    public String[] getSOPClasses();
+    
+    public String getSOPClass();
+    
+    public String getTransfCap();
+    
+    public int getMaxClientAssoc();
+    
+    public int getMaxPDULengthReceive();
+    
+    public int getMaxPDULenghtSend();
+    
+    public String getLocalAETName();
+    
+    public String getPermitedLocalInterfaces();
+    
+    public String getPermitedRemoteHostnames();
+    
+    public boolean isStorage();
+    
+    public boolean isQueryRetrive();
+    
+    public boolean isWANModeEnabled();
+    
+    public int getMaxMessages();
+    
+    public String getNetworkInterfaceAddress();
+    
+    public List<String> getNetworkInterfacesNames();
+    
+    public Map<String, Object> getStorageSettings();
+    
+    public Map<String, Object> getQueryRetrieveSettings();
+    
+    public Map<String, String> getModalityFind();
+
+    public List<MoveDestination> getMoves();
+
+    public Set<String> getPriorityAETitles();
+
+}
+
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/core/WebSettingsReader.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/WebSettingsReader.java
new file mode 100644
index 0000000..b7ac319
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/core/WebSettingsReader.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package pt.ua.dicoogle.sdk.core;
+
+/** A read-only interface for accessing web server settings.
+ *
+ * @author Eduardo Pinho <eduardopinho at ua.pt>
+ */
+public interface WebSettingsReader {
+
+    public boolean isWebServer();
+    
+    public int getServerPort();
+    
+    public String getAllowedOrigins();
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/DocumentIndexReport.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/DocumentIndexReport.java
new file mode 100644
index 0000000..e3ea2e7
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/DocumentIndexReport.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+public class DocumentIndexReport extends IndexReport {
+
+	private Measurable retrieveObjectTime;
+	private Measurable assembleDocumentTIme;
+	private Measurable storeInDatabaseTime;
+	private final Measurable totalTime;
+	private boolean successfull;
+	private final String id;
+			
+	public DocumentIndexReport(String id) {
+		super();
+		this.id = id;
+		this.totalTime = new Measurable();
+		this.successfull = true;
+	}
+	
+	private static void lazyInit(Measurable obj){
+		if(obj == null)
+			obj = new Measurable();
+	}	
+	
+	public Measurable getRetrieveObjectTime() {
+		lazyInit(retrieveObjectTime);
+		return retrieveObjectTime;
+	}
+
+	public Measurable getAssembleDocumentTIme() {
+		lazyInit(assembleDocumentTIme);
+		return assembleDocumentTIme;
+	}
+
+	public Measurable getStoreInDatabaseTime() {
+		lazyInit(storeInDatabaseTime);
+		return storeInDatabaseTime;
+	}
+	
+	public boolean isSuccessfull() {
+		return successfull;
+	}
+
+	public void setSuccessfull(boolean successfull) {
+		this.successfull = successfull;
+	}
+
+	public String getId() {
+		return id;
+	}
+	
+	public void start() {
+		totalTime.start();
+	}
+
+	public void stop() {
+		totalTime.stop();
+	}
+
+	@Override
+	public long getElapsedTime() {
+		return totalTime.getTime();
+	}
+
+	@Override
+	public int getNErrors() {
+		if(isSuccessfull())
+			return 0;
+		return 1;
+	}
+
+	@Override
+	public int getNIndexed() {		
+		if(isSuccessfull())
+			return 1;
+		return 0;
+	}
+
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport.java
new file mode 100644
index 0000000..a42a0c8
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+public abstract class IndexReport extends Report {
+
+	public abstract long getElapsedTime();
+
+	public abstract int getNErrors();
+
+	public abstract int getNIndexed();
+
+}
\ No newline at end of file
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport2.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport2.java
new file mode 100644
index 0000000..1acb3f0
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/IndexReport2.java
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+public class IndexReport2 extends IndexReport {
+
+	private int nIndexedFiles;
+	private int nErrors;
+	private long elapsedTime;
+	
+	public IndexReport2(int nIndexedFiles, int nErrors, long elapsedTime) {
+		super();
+		this.nIndexedFiles = nIndexedFiles;
+		this.nErrors = nErrors;
+		this.elapsedTime = elapsedTime;
+	}
+	
+	public IndexReport2(int nIndexedFiles, int nErrors) {
+		this(nIndexedFiles, nErrors, 0);
+	}
+	
+	public IndexReport2(int nIndexedFiles) {
+		this(nIndexedFiles, 0, 0);
+	}
+	
+	public IndexReport2() {
+		this(0,0,0);
+	}
+
+	public long getElapsedTime() {
+		return elapsedTime;
+	}
+
+	@Override
+	public String toString() {
+		return "IndexReport [nIndexedFiles=" + nIndexedFiles + ", nErrors="
+				+ nErrors + ", elapsedTime=" + elapsedTime + "]";
+	}
+
+	public void setnIndexedFiles(int nIndexedFiles) {
+		this.nIndexedFiles = nIndexedFiles;
+	}
+
+	public void setnErrors(int nErrors) {
+		this.nErrors = nErrors;
+	}
+
+	public void setElapsedTime(long elapsedTime) {
+		this.elapsedTime = elapsedTime;
+	}
+	
+	public void addIndexFile(){
+		this.nIndexedFiles++;
+	}
+	
+	public void addError(){
+		this.nErrors++;
+	}
+	
+	public void started(){
+		this.elapsedTime = System.currentTimeMillis();
+	}
+	
+	public void finished(){
+		this.elapsedTime = System.currentTimeMillis() - elapsedTime;
+	}
+
+	@Override
+	public int getNErrors() {
+		return nErrors;
+	}
+
+	@Override
+	public int getNIndexed() {
+		return nIndexedFiles;
+	}
+	
+
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Measurable.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Measurable.java
new file mode 100644
index 0000000..6712014
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Measurable.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+public class Measurable {
+	private long t;
+	
+	public void start(){
+		t = System.currentTimeMillis();
+	}
+	
+	public void stop(){
+		t = System.currentTimeMillis() - t;
+	}
+	
+	public long getTime(){
+		return t;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/MoveDestination.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/MoveDestination.java
new file mode 100755
index 0000000..18c4271
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/MoveDestination.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/** An immutable data structure for describing a DICOM node (potential C-MOVE destinations).
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class MoveDestination implements Serializable
+{
+    static final long serialVersionUID = 2L;
+
+    private final String AETitle;
+    private final String ipAddrs;
+    private final int port;
+
+    private final String description;
+    private final boolean isPublic;
+
+    public MoveDestination(String AETitle, String ipAddr, int port, boolean isPublic, String description) {
+        this.AETitle = AETitle;
+        this.ipAddrs = ipAddr;
+        this.port = port;
+        this.isPublic = isPublic;
+        this.description = description;
+    }
+
+    public MoveDestination(String AETitle, String ipAddr, int port, boolean isPublic) {
+        this(AETitle, ipAddr, port, isPublic, "");
+    }
+
+    public MoveDestination(String AETitle, String ipAddr, int port) {
+        this(AETitle, ipAddr, port, false, "");
+    }
+
+    /**
+     * @return the AETitle
+     */
+    public String getAETitle()
+    {
+        return AETitle;
+    }
+
+    /**
+     * @param AETitle the AETitle to set
+     */
+/*    public void setAETitle(String AETitle)
+    {
+        this.AETitle = AETitle;
+    }*/
+
+    /**
+     * @return the ipAddrs
+     */
+    public String getIpAddrs()
+    {
+        return ipAddrs;
+    }
+
+    /**
+     * @param ipAddrs the ipAddrs to set
+     */
+/*    public void setIpAddrs(String ipAddrs)
+    {
+        this.ipAddrs = ipAddrs;
+    } */
+
+    /**
+     * @return the port
+     */
+    public int getPort()
+    {
+        return port;
+    }
+
+    @Override
+    public String toString()
+    {
+        String result;
+        result = "MoveDestination AET: " + this.AETitle + " (" + this.ipAddrs + ":" +
+                String.valueOf(this.port) + ")";
+        if (!description.isEmpty()) {
+            result += " - " + this.description;
+        }
+        
+        return result ;
+    }
+
+
+    /**
+     * @return the description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * @return the isPublic
+     */
+    public boolean isIsPublic() {
+        return isPublic;
+    }
+
+    @Override
+    public boolean equals(Object obj){
+        if(obj == null || getClass() != obj.getClass())
+            return false;
+
+        if(obj == this)
+            return true;
+
+        MoveDestination move = (MoveDestination) obj;
+
+        // To the list of MoveDestinations may not be repeated AETitles
+        return move.AETitle.equals(AETitle) && move.ipAddrs.equals(ipAddrs) && move.port == port;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 97 * hash + Objects.hashCode(this.AETitle);
+        hash = 97 * hash + Objects.hashCode(this.ipAddrs);
+        hash = 97 * hash + this.port;
+        return hash;
+    }
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Report.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Report.java
new file mode 100644
index 0000000..1282192
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/Report.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+/**
+ *
+ * @author psytek
+ */
+public class Report {
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/SearchResult.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/SearchResult.java
new file mode 100755
index 0000000..84157d5
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/SearchResult.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+import java.io.Serializable;
+import java.net.URI;
+import java.util.HashMap;
+
+/**
+ * Simple holder class to store one hit from searches.
+ * 
+ * @author Marco
+ * @author Carlos Ferreira
+ * @author Pedro Bento
+ * modified by: Frederico Valente
+ */
+public class SearchResult implements Serializable {
+    private URI location; //a uri that allows us to fetch the result object
+    private double score; //score given by the querier
+    
+    //stores extra data, placed by specific plugins or inserted along the way
+    private HashMap<String, Object> extraData = new HashMap<>(); 
+
+    public SearchResult(URI location, double score, HashMap<String,Object> data){
+        this.location = location;
+        this.score = score;
+        
+        if(data != null)
+            this.extraData = data;
+    }
+    
+    
+    /**
+     * Gets the location of the hit
+     * @return URI pointing to dicom object
+     */
+    public URI getURI(){return location;}
+
+    
+    public Object get(String tag){
+        return extraData.get(tag);
+    }
+    
+    public void put(String tag, Object value){
+        extraData.put(tag, value);
+    }
+    
+    public <T> T getData(String extraFieldName){
+        Object ret = extraData.get(extraFieldName);
+        
+        if(ret == null) return null;
+         
+        try{
+            return (T) ret;
+        }
+        catch(ClassCastException e){
+            return null;
+        }
+    }
+    
+    /**
+     * Unlike what the name says, this does not returns the score.
+     * Unless it does. Ok, it does... which is most definitely weird given the method name.
+     * This score is a measure of *dissimilarity* 
+     * that is, a score of 0 should mean an exact hit
+     * 
+     * @return score of the result;
+     */
+    public double getScore(){return score;}
+    
+    /**
+     * Gets the extra documents fields
+     * @return the table containing the extra fields
+     */
+    public HashMap<String, Object> getExtraData(){return extraData;}
+
+    @Override
+    public String toString(){
+        return location.toString()+" "+score;
+    }
+    
+    
+    /*  Returns a tree made of hashmaps
+     * the first key is the patientName, the second the study, followed by series and image uri
+     * 
+     * todo: move the goddamned hash train to a class,
+     * just the definition of this makes me sick
+     */
+    public static HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> toTree(Iterable<SearchResult> results){
+        HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> tree = new HashMap<>();
+        
+        for(SearchResult r : results){
+            URI fileName = r.getURI();
+            String patientName = r.<String>getData("PatientName");
+            String studyUID = r.<String>getData("StudyInstanceUID");
+            String seriesUID = r.<String>getData("SeriesInstanceUID");
+            //we could have a SOPInstanceUID here but we use the search result itself as last element
+
+            if(patientName == null) patientName = "undefined PatientName";
+            else{patientName = patientName.trim();}
+            
+            if(studyUID == null) studyUID = "undefined StudyInstanceUID";
+            else{studyUID = studyUID.trim();}
+            
+            if(seriesUID == null) seriesUID = "undefined SeriesInstanceUID";
+            else{seriesUID = seriesUID.trim();}
+            
+            //check patient
+            if(tree.containsKey(patientName)){    
+                if(tree.get(patientName).containsKey(studyUID)){
+                    if(tree.get(patientName).get(studyUID).containsKey(seriesUID)){
+                        tree.get(patientName).get(studyUID).get(seriesUID).put(fileName.toString(), r);
+                    }
+                    else{
+                        HashMap<String, SearchResult> seriesResults = new HashMap<>();
+                        seriesResults.put(fileName.toString(), r);
+                        
+                        tree.get(patientName).get(studyUID).put(seriesUID, seriesResults);
+                    }
+                }
+                else{//no study
+                    HashMap<String, SearchResult> seriesResults = new HashMap<>();
+                    seriesResults.put(fileName.toString(), r);
+                
+                    HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>();
+                    studySeries.put(seriesUID, seriesResults);
+                
+                    tree.get(patientName).put(studyUID, studySeries);
+                }
+            }
+            else{//no patient name
+                HashMap<String, SearchResult> seriesResults = new HashMap<>();
+                seriesResults.put(fileName.toString(), r);
+                
+                HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>();
+                studySeries.put(seriesUID, seriesResults);
+                
+                HashMap<String, HashMap<String, HashMap<String,SearchResult>>> patientStudies = new HashMap<>();
+                patientStudies.put(studyUID, studySeries);
+                
+                tree.put(patientName, patientStudies);//add patient, study, series, image to tree
+            }
+        }
+        return tree;
+    }
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/TaskIndexReport.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/TaskIndexReport.java
new file mode 100644
index 0000000..810e524
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/datastructs/TaskIndexReport.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.datastructs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TaskIndexReport extends IndexReport {
+
+	private final List<DocumentIndexReport> successfulReports;
+	private final List<DocumentIndexReport> errorReports;
+	private boolean successful;
+	private final Measurable elapsedTime;
+	
+	public TaskIndexReport() {
+		// TODO Auto-generated constructor stub
+		this.successfulReports = new ArrayList<>();
+		this.errorReports = new ArrayList<>();
+		this.elapsedTime = new Measurable();
+		this.successful = true;
+	}
+	
+	public void addReport(DocumentIndexReport report){
+		if(report.isSuccessfull())
+			successfulReports.add(report);
+		else
+			errorReports.add(report);
+	}
+
+	public void start() {
+		elapsedTime.start();
+	}
+
+	public void stop() {
+		elapsedTime.stop();
+	}
+	
+	public void setSuccessful(boolean successful) {
+		this.successful = successful;
+	}
+
+	/* (non-Javadoc)
+	 * @see pt.ua.dicoogle.sdk.datastructs.IndexReport#getElapsedTime()
+	 */
+	@Override
+	public long getElapsedTime() {
+		return elapsedTime.getTime();
+	}
+	
+	/* (non-Javadoc)
+	 * @see pt.ua.dicoogle.sdk.datastructs.IndexReport#getNErrors()
+	 */
+	@Override
+	public int getNErrors(){
+		if(!successful)
+			return -1;
+		return this.errorReports.size();
+	}
+
+	/* (non-Javadoc)
+	 * @see pt.ua.dicoogle.sdk.datastructs.IndexReport#getNIndexed()
+	 */
+	@Override
+	public int getNIndexed(){
+		if(!successful)
+			return -1;
+		return this.successfulReports.size();
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/factory/PluginFactory.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/factory/PluginFactory.java
new file mode 100644
index 0000000..7275a5a
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/factory/PluginFactory.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.factory;
+
+import java.io.File;
+import java.util.Collection;
+import net.xeoh.plugins.base.PluginManager;
+import net.xeoh.plugins.base.impl.PluginManagerFactory;
+import net.xeoh.plugins.base.util.PluginManagerUtil;
+import pt.ua.dicoogle.sdk.PluginSet;
+
+/**
+ * 
+ * @author psytek
+ */
+
+public class PluginFactory {
+    public static Collection<PluginSet> getPlugins(){
+        File path = new File("Plugins");
+        return PluginFactory.getPlugins(path);
+    }
+    
+    public static Collection<PluginSet> getPlugins(File pluginDirectory){
+        PluginManager pm = PluginManagerFactory.createPluginManager();
+        //System.err.println(pluginDirectory.getAbsolutePath());
+        pm.addPluginsFrom(pluginDirectory.toURI());
+        PluginManagerUtil pmu = new PluginManagerUtil(pm);
+        return pmu.getPlugins(PluginSet.class);
+    }
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/ConfigurationHolder.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/ConfigurationHolder.java
new file mode 100644
index 0000000..e2aa275
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/ConfigurationHolder.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings;
+
+import java.io.File;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+
+
+/**
+ *
+ * @author tiago
+ */
+public class ConfigurationHolder {
+    private XMLConfiguration cnf;
+    
+    public ConfigurationHolder(File settingsFile) throws ConfigurationException{        
+        this(settingsFile, true);
+    }
+    
+    public ConfigurationHolder(File settingsFile, boolean autosave) throws ConfigurationException{        
+
+    	if(!settingsFile.exists()){
+    		cnf = new XMLConfiguration();
+    		cnf.setFile(settingsFile);
+    		cnf.save();
+    		cnf.setAutoSave(true);
+    	}else{
+    		cnf = new XMLConfiguration(settingsFile);
+	        cnf.setAutoSave(autosave); 
+	    }
+    }
+
+	public XMLConfiguration getConfiguration() {
+		return cnf;
+	}    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/CoreSettings.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/CoreSettings.java
new file mode 100644
index 0000000..b9079f4
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/CoreSettings.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings;
+
+/**
+ * Contains the list of Dicoogle Settings 
+ * 
+ * <p>
+ * <b> This list can be accessed by the Plugins</b>
+ * </p>
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface CoreSettings
+{
+    /**
+     * This option is related with the de-identification of the patient data
+     * If this option is enable the documents will be indexed and shown in an
+     * anonymous format. 
+     * @return boolean true if anonymize is enable, false otherwise. 
+     */
+    public boolean isIndexAnonymous();
+    
+    /**
+     * If this option is enable, the database will store a thumbnail of each 
+     * image 
+     * @return boolean true if is necessary to create thumbnail, false otherwise
+     */
+    public boolean isThumbnails();
+    /**
+     * Get the matrix size of the thumbnail
+     * 
+     * @return String matrix size in the format numberXnumber, for example,
+     * 8x8 or 16x16 pixels 
+     */
+    public String getThumbnailsMatrix();
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/InvalidSettingValueException.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/InvalidSettingValueException.java
new file mode 100644
index 0000000..2370db8
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/InvalidSettingValueException.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings;
+
+/**
+ * Handles the exception code to be used on the plugin settings assigning.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class InvalidSettingValueException extends RuntimeException
+{
+	private String paramName;
+
+	public InvalidSettingValueException(String message, String paramName)
+	{
+		super(message);
+
+		this.paramName = paramName;
+	}
+
+	public InvalidSettingValueException(String message)
+	{
+		super(message);
+
+		this.paramName = null;
+	}
+
+	public String getParamName()
+	{
+		return paramName;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Settings.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Settings.java
new file mode 100644
index 0000000..82e3ce8
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Settings.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author: Frederico Valente
+ * 
+ * This object will be serialized to disk before shutdown and on configuration save.
+ * 
+ */
+public class Settings{
+    
+    private static final Logger log = LoggerFactory.getLogger(Settings.class);
+    
+    File settingsXmlFile; //xml file handler
+    String settingsXmlString;//xml file contents
+    
+    /**
+     * 
+     * @param settingsXmlFile an xml file pointing to the settings
+     * @throws IOException 
+     */
+    public Settings(File settingsXmlFile) throws IOException{
+        log.debug("Loading settings from: {}", settingsXmlFile.getAbsolutePath());
+        this.settingsXmlFile = settingsXmlFile;
+        
+        //creates the settings file if it does not exist
+        if(!settingsXmlFile.exists()){
+            settingsXmlFile.createNewFile();
+            settingsXmlString = "";
+            return;
+        }
+        
+        reload();
+    }
+
+    /**
+     * Given an xml string (possibly from an editor), makes it the current settings and stores it in disk
+     * @param xml
+     * @throws IOException 
+     */
+    public void setXml(String xml) throws IOException{
+        settingsXmlString = xml;
+        save();
+    }
+    
+    /**
+     * reloads the xml file
+     */
+    public final void reload() throws IOException{
+        //we have a settings file, lets read it to the string
+        try (FileInputStream stream = new FileInputStream(settingsXmlFile)) {
+            FileChannel fc = stream.getChannel();
+            MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
+            String xmlSettings = Charset.defaultCharset().decode(bb).toString();
+            settingsXmlString = xmlSettings;
+        }
+        
+        log.debug("Settings for: {}", settingsXmlFile.getAbsolutePath());
+        log.debug(settingsXmlString);
+        log.debug("...");
+    }
+    
+    /**
+    * Saves the settings xml to disk (on the path provided to the constructor)
+    * TODO: this is poorly done, we should save to a tmp file and then move the files
+    * as opposed to just write on top of the old file
+    * TODO: also, we should validate the xml
+    */
+    public void save() throws IOException{
+        try(FileOutputStream fileOutputStream = new FileOutputStream(settingsXmlFile, true)){
+            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
+            bufferedOutputStream.write(settingsXmlString.getBytes(Charset.defaultCharset()));
+            bufferedOutputStream.flush();
+        }
+    }
+    
+    /**
+     * 
+     * @return the xml contents of the file
+     */
+    public String getXml(){return settingsXmlString;}
+    
+    /*
+     * Helper methods below
+     */
+    public String field(String name){return null;}
+    public int fieldAsInt(String name){return 0;}
+    public double fieldAsDouble(String name){return 0.0;}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Utils.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Utils.java
new file mode 100644
index 0000000..a3c1480
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/Utils.java
@@ -0,0 +1,272 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings;
+
+import java.util.Map;
+import java.util.HashMap;
+import org.apache.commons.lang3.StringEscapeUtils;
+import pt.ua.dicoogle.sdk.settings.types.GenericSetting;
+
+/**
+ * Helper for parsing form input values and creating HTML content based on them,
+ * server side.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class Utils
+{
+	/**
+	 * This converts and applies the new textual values into the originalSettings HashMap, taking into account their original class/type.
+	 * Only the settings that exist on both Maps are updated, this avoid invalid settings and Class type injections from happening.
+	 *
+	 * @param originalSettings the original advanced/internal settings of a plugin or service.
+	 * @param newSettings the new settings to apply.
+	 * @return the originalSettings HashMap with the new values in place (you can use the reference passed as originalSettings instead if you want, they will allways be the same).
+	 */
+	public static HashMap<String, Object> processAdvancedSettings(HashMap<String, Object> originalSettings, HashMap<String, String[]> newSettings)
+	{
+		for (Map.Entry<String, Object> setting : originalSettings.entrySet())
+		{
+			String name = getHTMLElementIDFromString(setting.getKey()); // NOTE remmember that the setting name is "kinda encoded" (and not in the URLEncode way, that's handled automagically)
+			Object value = setting.getValue();
+
+			if (newSettings.containsKey(name)) // if the setting is found on the request try to update its value (maintaining the same type ofc)
+			{
+				String[] newValue = newSettings.get(name);
+
+				if (value != null)
+				{
+					// parse the value depending on its class
+					if (value.getClass().equals(Integer.class))
+						value = Integer.valueOf(newValue[0]);
+					else if (value.getClass().equals(Float.class))
+						value = Float.valueOf(newValue[0]);
+					else if (value.getClass().equals(Boolean.class))
+						value = Boolean.valueOf(parseCheckBoxValue(newValue[0]));
+					else if (value instanceof GenericSetting)
+						value = ((GenericSetting) value).fromHTTPParams(newSettings, 0, name);
+					else // String or unrecognized class
+						value = newValue[0];
+
+					setting.setValue(value);
+				}
+				else // null is treated as String
+				{
+					value = newValue[0];
+
+					setting.setValue(value);
+				}
+
+			}
+			else // if the setting was not found check if it's a Boolean one, this is a FIX because browsers omit unchecked checkboxes on form action
+			{
+				if (value.getClass().equals(Boolean.class))
+					setting.setValue(new Boolean(false));
+				else if (value instanceof GenericSetting)
+				{
+					value = ((GenericSetting) value).fromHTTPParams(newSettings, 0, name);
+					setting.setValue(value);
+				}
+			}
+		}
+
+		return originalSettings; // just for easier use
+	}
+
+	/**
+	 * Given the string value of a checkbox obtained from an http request,
+	 * returns its boolean value.
+	 *
+	 * @param value the checkbox value obtained from an http request.
+	 * @return the checkbox state in boolean form.
+	 */
+	public static boolean parseCheckBoxValue(String value)
+	{
+		// default state is not checked
+		boolean result = false;
+
+		// if the value is defined
+		if ((value != null) && (! value.isEmpty()))
+			result = value.equalsIgnoreCase("On"); // check if it matches the "on" string
+
+		return result;
+	}
+
+	/**
+	 * Given the string value of a checkbox obtained from an http request,
+	 * returns its boolean value.
+	 *
+	 * @param values an array of Strings where the checkbox value obtained from an http request is.
+	 * @param index the index on the array where the wanted checkbox value is.
+	 * @return the checkbox state in boolean form.
+	 */
+	public static boolean parseCheckBoxValue(String[] values, int index)
+	{
+		// default state is not checked
+		boolean result = false;
+
+		// if the value is defined
+		if ((values != null) && (values.length > index))
+			result = parseCheckBoxValue(values[index]);
+
+		return result;
+	}
+
+	/**
+	 * Based on a input String, returns a valid HTML element name or ID for it.
+	 * <b>NOTE:</b> be aware that repeated calls with the same input String
+	 * will return the same result, so, on these cases name/ID collisions will happen!
+	 *
+	 * @param input the input String.
+	 * @return a valid HTML element ID or name.
+	 */
+	public static String getHTMLElementIDFromString(String input)
+	{
+		if ((input == null) || input.trim().isEmpty())
+			return input;
+
+		input = input.trim();
+
+		// the name must start with a letter, if it doesn't them add an "s" to it
+		if (! input.substring(0, 1).matches("[A-Za-z]"))
+			input = "s" + input;
+
+		// these are the whitelisted (valid) chars, replace all the others with nothing
+		return input.replaceAll("[^A-Za-z0-9-_]", "");
+	}
+
+	/**
+	 * Based on the "real" type/class of the plugin setting Object returns the appropriate form input for it.
+	 *
+	 * @param name the Form Name of this HTML input.
+	 * @param value a Object.
+	 * @param isArrayElement if this value Object is part of a another multiple value Object.
+	 * @return the appropriate form input for the supplied Object.
+	 */
+	public static String getHTMLInputFromType(String name, Object value, boolean isArrayElement)
+	{
+		String result = "<input name=\"" + name + (isArrayElement ? "[]" : "") + "\" ";
+
+		if (value == null)
+		{
+			result += "type=\"text\" value=\"\" />";
+		}
+		else if (value.getClass().equals(Integer.class))
+		{
+			result += "type=\"number\" value=\"" + ((Integer) value).intValue() + "\" />";
+		}
+		else if (value.getClass().equals(Float.class))
+		{
+			result += "type=\"number\" value=\"" + ((Float) value).floatValue() + "\" />";
+		}
+		else if (value.getClass().equals(Boolean.class))
+		{
+			result += "type=\"checkbox\" " + (((Boolean) value).booleanValue() ? "checked=\"checked\"" : "") + " />";
+		}
+		else if (value instanceof GenericSetting)
+		{
+			result = ((GenericSetting) value).toHTMLString(name + (isArrayElement ? "[]" : ""));
+		}
+		else
+		// NOTE add extra data type classes here, if needed
+		if (value.getClass().equals(String.class))
+		{
+			result += "type=\"text\" value=\"" + StringEscapeUtils.escapeHtml4((String) value) + "\" />";
+		}
+		else // unrecognized type/class
+		{
+			//throw new ClassCastException("Unsupported class \"" + value.getClass().getName() + "\"");
+			//result += "type=\"text\" value=\"" + StringEscapeUtils.escapeHtml4( value.toString()) + "\" />";
+			result += StringEscapeUtils.escapeHtml4( value.toString());			
+		}
+
+		return result;
+	}
+
+	/**
+	 * Based on the "real" type/class of the plugin setting Object returns the appropriate form input for it.
+	 * This procedure espects the value Object to not be a part of a another multiple value Object.
+	 *
+	 * @param id the ID and Name of this HTML input.
+	 * @param value a Object.
+	 * @return the appropriate form input for the supplied Object.
+	 */
+	public static String getHTMLInputFromType(String id, Object value)
+	{
+		return getHTMLInputFromType(id, value, false);
+	}
+
+	/**
+	 * Converts a String value into the type/class of originalValue.
+	 *
+	 * @param originalValue the original/target type/class of the value.
+	 * @param newValue the new value in String form.
+	 * @return a new Object of the same class as orignalValue but it's value updated to newValue.
+	 */
+	public static Object convertStringValueIntoProperType(Object originalValue, HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		Object result = null;
+
+		if (originalValue == null)
+		{
+			result = null;
+		}
+		else if (originalValue.getClass().equals(Integer.class))
+		{
+			String[] values = params.get(htmlElementID);
+			if ((values == null) || (values.length <= index) || (params.get(htmlElementID)[index] == null) || (params.get(htmlElementID)[index].isEmpty()))
+				result = 0;
+			else
+				result = Integer.valueOf(params.get(htmlElementID)[index]);
+		}
+		else if (originalValue.getClass().equals(Float.class))
+		{
+			String[] values = params.get(htmlElementID);
+			if ((values == null) || (values.length <= index) || (params.get(htmlElementID)[index] == null) || (params.get(htmlElementID)[index].isEmpty()))
+				result = 0.0F;
+			else
+				result = Float.valueOf(params.get(htmlElementID)[index]);
+		}
+		else if (originalValue.getClass().equals(Boolean.class))
+		{
+			String[] values = params.get(htmlElementID);
+			if ((values == null) || (values.length <= index) || (params.get(htmlElementID)[index] == null) || (params.get(htmlElementID)[index].isEmpty()))
+				result = false;
+			else
+				result = Boolean.valueOf(params.get(htmlElementID)[index]);
+		}
+		else if (originalValue instanceof GenericSetting)
+		{
+			result = ((GenericSetting) originalValue).fromHTTPParams(params, index, htmlElementID);
+		}
+		else
+		// NOTE add extra data type classes here, if needed
+		if (originalValue.getClass().equals(String.class))
+		{
+			result = params.get(htmlElementID)[index];
+		}
+		else // unrecognized type/class
+		{
+			//throw new ClassCastException("Unsupported class \"" + value.getClass().getName() + "\"");
+			result = originalValue;
+		}
+
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/CheckboxWithHint.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/CheckboxWithHint.java
new file mode 100644
index 0000000..a1c0375
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/CheckboxWithHint.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+
+import pt.ua.dicoogle.sdk.settings.Utils;
+
+/**
+ * Implements a regular checkbox with the addition of a mouse hint.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class CheckboxWithHint implements GenericSetting
+{
+	private String id;
+	private boolean checked;
+	private String text;
+	private String hint;
+
+	public CheckboxWithHint(String id, boolean checked, String text) {
+		super();
+		this.id = id;
+		this.checked = checked;
+		this.text = text;
+	}
+
+	public CheckboxWithHint(boolean checked, String text, String hint)
+	{
+		this.checked = checked;
+		this.text = text;
+		this.hint = hint;
+	}
+
+	/**
+	 * @return the checked
+	 */
+	public boolean isChecked()
+	{
+		return checked;
+	}
+
+	/**
+	 * @param checked the checked to set
+	 */
+	public void setChecked(boolean checked)
+	{
+		this.checked = checked;
+	}
+
+	/**
+	 * @return the text
+	 */
+	public String getText()
+	{
+		return text;
+	}
+
+	/**
+	 * @return the hint
+	 */
+	public String getHint()
+	{
+		return hint;
+	}
+
+	public String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<label class=\"checkbox\" title=\"" + StringEscapeUtils.escapeHtml4(hint) + "\">";
+		result +=	"<input type=\"checkbox\" id=\"" + htmlElementID + "\" name=\"" + htmlElementID + "\" " + (checked ? "checked=\"checked\"" : "") + " /> " + StringEscapeUtils.escapeHtml4(text);
+		result += "</label>";
+
+		return result;
+	}
+
+	public CheckboxWithHint fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		CheckboxWithHint result = new CheckboxWithHint(this.checked, this.text, this.hint);
+
+		result.setChecked(Utils.parseCheckBoxValue(params.get(htmlElementID), index));
+
+		return result;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ComboBox.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ComboBox.java
new file mode 100644
index 0000000..0139357
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ComboBox.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.apache.commons.lang3.StringEscapeUtils;
+
+/**
+ * Implements a combobox, multiple elements, with different values, may be added.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class ComboBox implements GenericSetting
+{
+	private HashMap<String, String> elements;
+	private String current;
+
+	public ComboBox()
+	{
+		elements = new LinkedHashMap<String, String>();
+		current = "";
+	}
+
+	public synchronized void addElement(String name, String value)
+	{
+		elements.put(name, value);
+	}
+
+	public synchronized void setCurrent(String name)
+	{
+		current = name;
+	}
+
+	public String getCurrent()
+	{
+		return current;
+	}
+
+	/**
+	 * Returns the value of the currently selected element.
+	 *
+	 * @return the value of the currently selected element, null if the
+	 * element is invalid or no element is currently selected.
+	 */
+	public String getCurrentValue()
+	{
+		for (Map.Entry<String, String> elem : elements.entrySet())
+		{
+			if (current.equalsIgnoreCase(elem.getKey()))
+				return elem.getValue();
+		}
+
+		return null;
+	}
+
+	public void setCurrentByValue(String value)
+	{
+		if (value == null)
+			current = "";
+
+		for (Map.Entry<String, String> elem : elements.entrySet())
+		{
+			if (value.equalsIgnoreCase(elem.getValue()))
+			{
+				current = elem.getKey();
+				return;
+			}
+		}
+
+		// if value not found, no change is made
+	}
+
+	public String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<select id=\"" + htmlElementID + "\" name=\"" + htmlElementID + "\">";
+		for (Map.Entry<String, String> elem : elements.entrySet())
+		{
+			result += "<option value=\"" + StringEscapeUtils.escapeHtml4(elem.getValue()) + "\" "+ ((current.equalsIgnoreCase(elem.getKey())) ? "selected=\"selected\"" : "" ) + ">";
+			result += StringEscapeUtils.escapeHtml4(elem.getKey());
+			result += "</option>";
+		}
+		result += "</select>";
+
+		return result;
+	}
+
+	@Override
+	public synchronized Object clone()
+	{
+		ComboBox result = new ComboBox();
+
+		result.current = this.current;
+		result.elements.putAll(this.elements);
+
+		return result;
+	}
+
+	public ComboBox fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		ComboBox result = (ComboBox) this.clone();
+
+		String[] values = params.get(htmlElementID);
+		if ((values != null) && (values.length > index))
+			result.setCurrentByValue(values[index]);
+
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/DataTable.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/DataTable.java
new file mode 100644
index 0000000..13c4694
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/DataTable.java
@@ -0,0 +1,337 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+import org.apache.commons.lang3.StringEscapeUtils;
+import pt.ua.dicoogle.sdk.settings.Utils;
+
+/**
+ * Handles a data (type) that is suposed to be on a table form.
+ * Supports multiple fields per row, and allows row coppies of the first row to
+ * be made and appended to the table. The user can also rows (except the first one).
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class DataTable implements GenericSetting
+{
+	/**
+	 * Column names.
+	 */
+	private String[] columns;
+	/**
+	 * Cell data.
+	 */
+	private Object[][] data;
+
+	/**
+	 * Creates a DataTable with no columns nor cells.
+	 */
+	public DataTable()
+	{
+		columns = new String[0];
+		data = new Object[0][0];
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns.
+	 *
+	 * @param columnCount the initial number of columns.
+	 */
+	public DataTable(int columnCount)
+	{
+		columns = new String[columnCount];
+		data = new String[0][columnCount];
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns and (empty) rowCount rows.
+	 *
+	 * @param columnCount the initial number of columns.
+	 * @param rowCount the initial number of rows.
+	 */
+	public DataTable(int columnCount, int rowCount)
+	{
+		columns = new String[columnCount];
+		data = new Object[rowCount][columnCount];
+	}
+
+	/**
+	 * Returns the column count on this DataTable.
+	 *
+	 * @return the column count on this DataTable.
+	 */
+	public synchronized int getColumnCount()
+	{
+		return columns.length;
+	}
+
+	/**
+	 * Returns the row count on this DataTable.
+	 *
+	 * @return the row count on this DataTable.
+	 */
+	public synchronized int getRowCount()
+	{
+		return data.length;
+	}
+
+	/**
+	 * Validates a column index for later use.
+	 *
+	 * @param index the index (zero based) of the target column.
+	 */
+	public synchronized boolean isValidColumnIndex(int index)
+	{
+		return ((index >= 0) && (index < columns.length));
+	}
+
+	/**
+	 * Validates a cell index for later use.
+	 *
+	 * @param row the row index (zero based) of the target cell.
+	 * @param column the column index (zero based) of the target cell.
+	 */
+	public synchronized boolean isValidCellIndex(int row, int column)
+	{
+		return (isValidColumnIndex(column) && ((row >= 0) && (row < data.length)));
+	}
+
+	/**
+	 * Adds a new (unamed) column at the end of the column list.
+	 */
+	public synchronized void addColumn()
+	{
+		// create a bigger sized array
+		String[] newColumns = new String[columns.length + 1];
+		Object[][] newData = new Object[data.length][columns.length + 1];
+
+		// copy all the previous data
+		System.arraycopy(columns, 0, newColumns, 0, columns.length);
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// set the new data as the current one
+		columns = newColumns;
+		data = newData;
+	}
+
+	/**
+	 * Adds a new column at the end of the column list.
+	 *
+	 * @param name the name/title of the new column.
+	 */
+	public synchronized void addColumn(String name)
+	{
+		// create a bigger sized array
+		String[] newColumns = new String[columns.length + 1];
+		Object[][] newData = new Object[data.length][columns.length + 1];
+
+		// copy all the previous data
+		System.arraycopy(columns, 0, newColumns, 0, columns.length);
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// add the new data
+		newColumns[columns.length] = name;
+
+		// set the new data as the current one
+		columns = newColumns;
+		data = newData;
+	}
+
+	/**
+	 * Returns the selected column name to the desired one.
+	 * Returns null if the the column index is not valid.
+	 *
+	 * @param column the index (zero based) of the target column.
+	 * @return the selected column name to the desired one.
+	 */
+	public synchronized String getColumnName(int column)
+	{
+		if (! isValidColumnIndex(column))
+			return null;
+
+		return columns[column];
+	}
+
+	/**
+	 * Changes the selected column name to the desired one.
+	 * Gracefully aborts if the the column index is not valid.
+	 *
+	 * @param column the index (zero based) of the target column.
+	 * @param name the desired new name for the column.
+	 */
+	public synchronized void setColumnName(int column, String name)
+	{
+		if (! isValidColumnIndex(column))
+			return;
+
+		columns[column] = name;
+	}
+
+	/**
+	 * Adds a new (empty) row at the end of the table.
+	 */
+	public synchronized void addRow()
+	{
+		// create a bigger sized array
+		Object[][] newData = new Object[data.length + 1][columns.length];
+
+		// copy all the previous data
+		for (int i = 0; i < data.length; i++)
+			System.arraycopy(data[i], 0, newData[i], 0, columns.length);
+
+		// set the new data as the current one
+		data = newData;
+	}
+
+	/**
+	 * Changes the selected cell data to the desired one.
+	 * Gracefully aborts if the the cell location is not valid.
+	 *
+	 * @param row the row index (zero based) of the target cell.
+	 * @param column the column index (zero based) of the target cell.
+	 * @param data the new data for the target cell.
+	 */
+	public synchronized void setCellData(int row, int column, Object data)
+	{
+		if (! isValidCellIndex(row, column))
+			return;
+
+		this.data[row][column] = data;
+	}
+
+	/**
+	 * Returns the selected cell data.
+	 *
+	 * @param row the row index (zero based) of the wanted cell.
+	 * @param column the column index (zero based) of the wanted cell.
+	 * @return null if the wanted cell is invalid, an otherwise Object.
+	 */
+	public synchronized Object getCellData(int row, int column)
+	{
+		if (! isValidCellIndex(row, column))
+			return null;
+
+		return this.data[row][column];
+	}
+
+	// Output formats ------------------------------------------------------
+
+	@Override
+	public synchronized String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<div id=\"" + htmlElementID + "\" class=\"data-table\">";
+
+		// loop through all the rows and add their cell data and column name to the result
+		for (int row = 0; row < data.length; row++)
+		{
+			result += "<div class=\"data-table-row\">";
+
+			for (int column = 0; column < columns.length; column++)
+			{
+				String columnID = Utils.getHTMLElementIDFromString(htmlElementID + " " + columns[column]);
+
+				result += "<div style=\"margin-right: 6px; display: inline-block;\">";
+				result +=	"<span>";
+				result +=		StringEscapeUtils.escapeHtml4(columns[column]);
+				result +=	"</span>";
+				result +=	"<span style=\"padding-left: 4px;\">";
+				result +=		Utils.getHTMLInputFromType(columnID, data[row][column], true);
+				result +=	"</span>";
+				result += "</div>";
+			}
+
+			// add a button to remove each element, except the first one
+			result += 	"<button type=\"button\" class=\"btn btn-small btn-danger removeButton\" onclick=\"removeDataTableRow(this.parentNode.parentNode, this.parentNode);\" " + ((row == 0) ? "hidden style=\"display: none !important;\"" : "") + ">Remove</button>";
+
+			result += "</div>";
+		}
+
+		result += "</div>";
+
+		// add one button to add another element to the table
+		result += "<button type=\"button\" class=\"btn btn-small btn-success\" onclick=\"addDataTableRow(document.getElementById('" + htmlElementID + "'));\">Add</button><br />"; // FIXME replace the getelementbyid with this.previoussibling ?!? http://www.w3schools.com/dom/prop_element_previoussibling.asp
+
+		return result;
+	}
+
+	// Input formats -------------------------------------------------------
+
+	/**
+	 * Based on a list of http request form (names & values) and a original value object,
+	 * parse the first ones to match the second ones format with the new values.
+	 *
+	 * @param original the original DataTable.
+	 * @param params the new params, and their values, to put into the DataTable.
+	 * @return a new DataTable with the updated cell information.
+	 */
+	@Override
+	public DataTable fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		// find how many rows the new params list has
+		// NOTE see the FIXME bellow to understand the need for two counters
+		int paramsCountMin = Integer.MAX_VALUE;
+		int paramsCountMax = Integer.MIN_VALUE;
+		for (String[] list : params.values()) // list all the params, and find the one that has the bigger and smaller amount of values
+		{
+			if (list.length < paramsCountMin)
+				paramsCountMin = list.length;
+			if (list.length > paramsCountMax)
+				paramsCountMax = list.length;
+		}
+
+		// create a new DataTable with the same column size as the original one and the same row count as the new params
+		DataTable result = new DataTable(this.getColumnCount(), paramsCountMax);
+
+		// add all the columns titles/names
+		for (int i = 0; i < result.getColumnCount(); i++)
+			result.setColumnName(i, this.columns[i]);
+
+		// add all the cells information available on the original DataTable
+		for (int j = 0; j < result.getColumnCount(); j++)
+		{
+			String columnID = Utils.getHTMLElementIDFromString(htmlElementID + " " + result.columns[j]) + "[]";
+			boolean hasNewValues = params.containsKey(columnID);
+
+			for (int i = 0; i < result.getRowCount(); i++)
+			{
+				Object cellData = this.data[0][j];
+
+				// if there is a new value for this cell then use it
+				if (hasNewValues)
+				{
+					cellData = Utils.convertStringValueIntoProperType(cellData, params, i, columnID);
+					// FIMXE if paramsCountMax is different of paramsCountMin them some column might not have all param values
+					//	this is true if boolean column are used, but browsers don't usually report back the uncheked boxes
+					//	so extra logic must be applied to fix this issue with boolean values
+					//	the problem relies on how do we know in what row is the value missing?
+				}
+
+				result.setCellData(i, j, cellData);
+			}
+		}
+
+		// return the newly formed DataTable
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/GenericSetting.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/GenericSetting.java
new file mode 100644
index 0000000..621db1d
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/GenericSetting.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+
+/**
+ * A generic data/setting type/class.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public interface GenericSetting
+{
+	// Output formats ------------------------------------------------------
+
+	/**
+	 * Outputs the current setting onto an HTML formated string, that can be
+	 * embeded onto a webpage.
+	 *
+	 * @param htmlElementID the ID name of the this HTML element.
+	 * @return an HTML formated string, that can be embeded onto a webpage.
+	 */
+	public String toHTMLString(String htmlElementID);
+
+	// Input formats -------------------------------------------------------
+
+	/**
+	 * Based on a list of HTTP request form (names & values) and the original
+	 * value object (of same type/class), parse the later to match the former
+	 * format with the new values. The original setting will be the object where
+	 * this function gets called at.
+	 *
+	 * @param params the new params, and their values, to put into the return object.
+	 * @param index the param index where the value is.
+	 * @return a new GenericSetting with the updated information.
+	 */
+	public GenericSetting fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID);
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/RangeInteger.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/RangeInteger.java
new file mode 100644
index 0000000..ebfa71d
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/RangeInteger.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+
+/**
+ * Implements an Integer ranged setting.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class RangeInteger implements GenericSetting
+{
+	private int min;
+	private int max;
+	private int value;
+
+	public RangeInteger(int min, int max)
+	{
+		this.min = min;
+		this.max = max;
+		this.value = min;
+	}
+
+	public RangeInteger(int min, int max, int value)
+	{
+		this.min = min;
+		this.max = max;
+		this.value = value;
+	}
+
+	/**
+	 * @return the min
+	 */
+	public int getMin()
+	{
+		return min;
+	}
+
+	/**
+	 * @return the max
+	 */
+	public int getMax()
+	{
+		return max;
+	}
+
+	/**
+	 * @return the value
+	 */
+	public int getValue()
+	{
+		return value;
+	}
+
+	/**
+	 * @param value the value to set
+	 */
+	public void setValue(int value)
+	{
+		this.value = value;
+	}
+
+	public String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<input type=\"range\" id=\"" + htmlElementID + "\" name=\"" + htmlElementID + "\" value=\"" + value + "\" min=\"" + min + "\" max=\"" + max + "\" />";
+
+		return result;
+	}
+
+	public RangeInteger fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		RangeInteger result = new RangeInteger(this.min, this.max, this.value);
+
+		result.setValue(Integer.parseInt(params.get(htmlElementID)[index]));
+
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ServerDirectoryPath.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ServerDirectoryPath.java
new file mode 100644
index 0000000..f5bb544
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/ServerDirectoryPath.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+
+/**
+ * Handles a data (type) that is suposed to contain a directory path located on the server.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class ServerDirectoryPath implements GenericSetting
+{
+	private String path;
+
+	public ServerDirectoryPath()
+	{
+		this.path = null;
+	}
+
+	public ServerDirectoryPath(String path)
+	{
+		this.path = path;
+	}
+
+	/**
+	 * @return the path
+	 */
+	public String getPath()
+	{
+		return path;
+	}
+
+	/**
+	 * @param path the path to set
+	 */
+	public void setPath(String path)
+	{
+		this.path = path;
+	}
+
+	// Output formats ------------------------------------------------------
+
+	public synchronized String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<select id=\"" + htmlElementID + "ds\" size=\"5\" class=\"span5\" style=\"display: none;\">";
+		result += "</select>";
+		result += "<div class=\"input-append\">";
+			result += "<input class=\"span4\" type=\"text\" id=\"" + htmlElementID + "\" name=\"" + htmlElementID + "\" value=\"" + path + "\" />";
+			result += "<button type=\"button\" class=\"btn\" onclick=\"showDirList(document.getElementById('" + htmlElementID + "ds'), document.getElementById('" + htmlElementID + "'), this);\">";
+				result += "<i class=\"icon-folder-open\"></i> Browse...";
+			result += "</button>";
+		result += "</div>";
+
+		return result;
+	}
+
+	// Input formats -------------------------------------------------------
+
+	/**
+	 * Based on a list of http request form (names & values) and a original value object,
+	 * parse the first ones to match the second ones format with the new values.
+	 *
+	 * @param original the original DataTable.
+	 * @param params the new params, and their values, to put into the DataTable.
+	 * @param index the param index where the value is.
+	 * @return a new DataTable with the updated cell information.
+	 */
+	public ServerDirectoryPath fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		// create a new DataTable with the same column size as the original one and the same row count as the new params
+		ServerDirectoryPath result = new ServerDirectoryPath(this.path);
+
+		result.setPath(params.get(htmlElementID)[index]);
+
+		// return the newly formed DataTable
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/StaticDataTable.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/StaticDataTable.java
new file mode 100644
index 0000000..14608db
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/settings/types/StaticDataTable.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.settings.types;
+
+import java.util.HashMap;
+import pt.ua.dicoogle.sdk.settings.Utils;
+
+/**
+ * Handles a data (type) that is suposed to be on a table form.
+ * Supports multiple fields per row.
+ * The contents of this table cannot be modified by the end user on the HTML interface.
+ *
+ * @author António Novo <antonio.novo at ua.pt>
+ */
+public class StaticDataTable extends DataTable
+{
+	/**
+	 * Creates a DataTable with no columns nor cells.
+	 */
+	public StaticDataTable()
+	{
+		super();
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns.
+	 *
+	 * @param columnCount the initial number of columns.
+	 */
+	public StaticDataTable(int columnCount)
+	{
+		super(columnCount);
+	}
+
+	/**
+	 * Creates a DataTable with (unamed) columnCount columns and (empty) rowCount rows.
+	 *
+	 * @param columnCount the initial number of columns.
+	 * @param rowCount the initial number of rows.
+	 */
+	public StaticDataTable(int columnCount, int rowCount)
+	{
+		super(columnCount, rowCount);
+	}
+
+	// Output formats ------------------------------------------------------
+
+	@Override
+	public synchronized String toHTMLString(String htmlElementID)
+	{
+		String result = "";
+
+		result += "<div id=\"" + htmlElementID + "\" class=\"data-table\">";
+
+		// loop through all the rows and add their cell data and column name to the result
+		for (int row = 0; row < this.getRowCount(); row++)
+		{
+			result += "<div class=\"data-table-row\">";
+
+			for (int column = 0; column < this.getColumnCount(); column++)
+			{
+				String cellID = Utils.getHTMLElementIDFromString(htmlElementID + this.getColumnName(column) + row);
+
+				result +=		Utils.getHTMLInputFromType(cellID, this.getCellData(row, column), false);
+			}
+
+			result += "</div>";
+		}
+
+		result += "</div>";
+
+		return result;
+	}
+
+	// Input formats -------------------------------------------------------
+
+	/**
+	 * Based on a list of http request form (names & values) and a original value object,
+	 * parse the first ones to match the second ones format with the new values.
+	 *
+	 * @param original the original DataTable.
+	 * @param params the new params, and their values, to put into the DataTable.
+	 * @return a new DataTable with the updated cell information.
+	 */
+	@Override
+	public StaticDataTable fromHTTPParams(HashMap<String, String[]> params, int index, String htmlElementID)
+	{
+		// create a new DataTable with the same column size as the original one and the same row count as the new params
+		StaticDataTable result = new StaticDataTable(this.getColumnCount(), this.getRowCount());
+
+		// add all the columns titles/names
+		for (int i = 0; i < result.getColumnCount(); i++)
+			result.setColumnName(i, this.getColumnName(i));
+
+		// add all the cells information available on the original DataTable
+		for (int column = 0; column < result.getColumnCount(); column++)
+		{
+			for (int row = 0; row < result.getRowCount(); row++)
+			{
+				String cellID = Utils.getHTMLElementIDFromString(htmlElementID + result.getColumnName(column)) + row;
+				Object cellData = this.getCellData(row, column);
+
+				cellData = Utils.convertStringValueIntoProperType(cellData, params, 0, cellID);
+
+				result.setCellData(row, column, cellData);
+			}
+		}
+
+		// return the newly formed DataTable
+		return result;
+	}
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/task/JointQueryTask.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/JointQueryTask.java
new file mode 100644
index 0000000..b7cef77
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/JointQueryTask.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.task;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ * Advanced task which encompases multiple sub-tasks.
+ * 
+ * This class helps dicoogle to deal with multiple providers simultaneously.
+ * 
+ * @author Tiago Marques Godinho, tmgodinho at ua.pt
+ *
+ */
+public abstract class JointQueryTask {
+
+	private boolean cancelled;
+	private int numberOfCompletedTasks;
+	
+	private List<Task<Iterable<SearchResult>>> searchTasks;
+	
+	public JointQueryTask() {
+		this.searchTasks = new ArrayList<>();
+		this.numberOfCompletedTasks = 0;
+		this.cancelled = false;
+	}
+
+	public boolean addTask(final Task<Iterable<SearchResult>> e) {
+		//Add hook
+		e.onCompletion( new Runnable() {
+			@Override
+			public void run() {
+				numberOfCompletedTasks++;
+				onReceive(e);
+				if(numberOfCompletedTasks == searchTasks.size())
+					onCompletion();
+			}
+		} );
+		
+		return searchTasks.add(e);
+	}
+	
+	public abstract void onCompletion();
+
+	public abstract void onReceive(Task<Iterable<SearchResult>> e);
+	
+	public Iterable<SearchResult> get() throws InterruptedException, ExecutionException{
+		List<SearchResult> list = new ArrayList<>();
+		
+		for(Task<Iterable<SearchResult>> task : searchTasks){
+			Iterable<SearchResult> res = task.get();
+			for(SearchResult i : res)
+				list.add(i);
+		}
+		return list;
+	}	
+
+	public float getProgress() {
+		if(isCancelled())
+			return -1;
+		
+		if(isDone())
+			return 1;
+		
+		return numberOfCompletedTasks / searchTasks.size();
+	}
+
+	public boolean isCancelled() {
+		return cancelled;
+	}
+
+	public boolean isDone() {
+		return numberOfCompletedTasks == searchTasks.size();
+	}
+
+	public boolean cancel(boolean mayInterruptIfRunning) {
+		boolean ret = true;
+		for(Task<Iterable<SearchResult>> t : searchTasks){
+			if(!t.isCancelled())
+				ret = t.cancel(mayInterruptIfRunning) && ret;
+		}
+		return ret;
+	}	
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/task/ProgressCallable.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/ProgressCallable.java
new file mode 100644
index 0000000..8821252
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/ProgressCallable.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.task;
+
+import java.util.concurrent.Callable;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public interface ProgressCallable<T> extends Callable<T>
+{
+    
+    
+    /**
+     * returns the task progress, goes from 0 to 1
+     * however, if we have an unbounded task a -1 is returned
+     */
+    public float getProgress();
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/task/Task.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/Task.java
new file mode 100644
index 0000000..656268a
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/task/Task.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.task;
+
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/** An entity for describing an asynchronous task in Dicoogle.
+ *
+ * @param <Type> the return type of the FutureTask
+ * 
+ * @author psytek
+ */
+public class Task<Type> extends FutureTask<Type> {
+
+    private String taskName = "unnamed task";
+    private Callable callable;
+    ArrayList<Runnable> toRunWhenComplete;
+    
+    public Task(Callable<Type> c){
+        super(c);
+        callable = c;
+        toRunWhenComplete = new ArrayList<>();//we could lazy initialize this in onCompletion
+    }
+    
+    public Task(String name, Callable<Type> c){
+        super(c);
+        taskName = name;
+        toRunWhenComplete = new ArrayList<>();//we could lazy initialize this in onCompletion
+    }
+    
+    @Override
+    protected void set(Type ret){
+        super.set(ret);
+        for(Runnable r : toRunWhenComplete){
+            r.run();
+        }
+    }
+    
+    public void onCompletion(Runnable r){
+        toRunWhenComplete.add(r);
+    }
+    
+    /** Gets the task's name
+     * @return a task name, for presentation purposes
+     */
+    public String getName(){return this.taskName;}
+    
+    /** Sets the task's name
+     * @param name the new task's name, for presentation purposes
+     */
+    public void setName(String name){this.taskName = name;}
+    
+    /** Gets the task's progress
+     * @return the task's progress from 0 to 1, or -1 if the task is unbounded
+     */
+    public float getProgress(){
+        if (callable instanceof ProgressCallable){
+            return ((ProgressCallable)this.callable).getProgress();
+        }
+        return -1;
+    }
+    
+}
+
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/DictionaryAccess.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/DictionaryAccess.java
new file mode 100755
index 0000000..b1e14d5
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/DictionaryAccess.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.utils;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.dcm4che2.data.Tag;
+
+/**
+ *
+ * @author Lu??s A. Basti??o Silva <bastiao at ua.pt>
+ */
+public class DictionaryAccess
+{
+
+    private HashMap<String, Integer> tagList = new HashMap<String, Integer>();
+    private HashMap<Integer, String> tagListByTag = new HashMap<Integer, String>();
+
+    
+    private static final DictionaryAccess instance =  new DictionaryAccess(); ;
+
+    public static DictionaryAccess getInstance()
+    {
+        return instance;
+    }
+
+    private DictionaryAccess()
+    {
+    	
+        Field [] tags = Tag.class.getFields();
+        for (int i = 0 ; i<tags.length; i++)
+        {
+            try {
+                tagList.put(tags[i].getName(), tags[i].getInt(null));
+                tagListByTag.put(tags[i].getInt(null),tags[i].getName());
+            } catch (IllegalArgumentException ex) {
+                LoggerFactory.getLogger(DictionaryAccess.class).error(ex.getMessage(), ex);
+            } catch (IllegalAccessException ex) {
+                LoggerFactory.getLogger(DictionaryAccess.class).error(ex.getMessage(), ex);
+            }
+        }
+    }
+
+    public String tagName(int tag)
+    {
+        return this.tagListByTag.get(tag);
+    }
+
+    public String toString()
+    {
+        String str = "" ;
+        Iterator<String> it = (Iterator<String>) getTagList().keySet().iterator();
+        while(it.hasNext())
+        {
+            String key = it.next();
+            str+="Name: " + key + " with value: " +
+                    Integer.toHexString( this.getTagList().get(key));
+        }
+        return str ;
+    }
+
+
+    /*public static void  main(String args[]) throws IllegalArgumentException, IllegalAccessException
+    {
+        DictionaryAccess da = new DictionaryAccess();
+        
+    }*/
+
+    /**
+     * @return the tagList
+     */
+    public HashMap<String, Integer> getTagList() {
+        return tagList;
+    }
+
+    /**
+     * @param tagList the tagList to set
+     */
+    public void setTagList(HashMap<String, Integer> tagList) {
+        this.tagList = tagList;
+    }
+
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagValue.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagValue.java
new file mode 100755
index 0000000..9b17be3
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagValue.java
@@ -0,0 +1,197 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.utils;
+
+import java.io.Serializable;
+
+import org.apache.commons.lang3.StringUtils;
+import org.dcm4che2.data.BasicDicomObject;
+import org.dcm4che2.data.VR;
+
+/**
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ */
+public class TagValue implements Serializable {
+
+    static final long serialVersionUID = 1L;
+    
+    /** tag value - (group, subgroup) in hex coding */ 
+    private int tag = 0  ;
+    /** Public name like Patient Name */
+    private String name = null ;
+    /** Alias to the name like PatientName */
+    private String alias = null ;
+
+    /**  ValueRepresentation */
+    private String tgVR = null ;
+    /** RetiredStatus - Deprecated mode */
+    private int   ret  = 0 ;
+
+    /** Value Multiciply */
+    private int VM = 0 ;
+
+    public TagValue(int tag, String alias)
+    {
+        this.tag = tag ;
+        this.name = alias;
+        this.alias = alias ;
+        
+        VR tagVR = (new BasicDicomObject()).vrOf(tag);
+        
+        if(tagVR != null)
+            tgVR = tagVR.toString();
+    }
+    /**
+     * Get The Tag Number (group, subgroup)
+     * @return int
+     */
+    public int getTagNumber()
+    {
+        return this.tag  ;
+    }
+    
+    public String getTagID(){
+    	return StringUtils.leftPad(Integer.toHexString(tag), 8, '0');
+    }
+    /**
+     * A formal name
+     * @return String
+     */
+    public String getName()
+    {
+        return this.name ;
+    }
+    /**
+     * Alias
+     * @return String
+     */
+    public String getAlias()
+    {
+        return this.alias ;
+    }
+    /**
+     * Verify if it is deprecated
+     * @return int
+     */
+    public int getRet()
+    {
+        return this.ret ;
+    }
+
+    public String getGroup()
+    {
+        return TagValue.getGroup(tag);
+    }
+
+    public String getSubgroup()
+    {
+        return TagValue.getSubgroup(tag);
+    }
+    
+    public static String getGroup(int tag)
+    {
+        String result = Integer.toHexString(
+                (tag & 0xFFFF0000 )>> 16) ;
+        return StringUtils.leftPad(result, 4, '0');
+    }
+
+    public static String getSubgroup(int tag)
+    {
+        String result =  Integer.toHexString(tag & 0x0000FFFF ) ;
+        return StringUtils.leftPad(result, 4, '0');
+    }
+
+    /**
+     * @return the VR
+     */
+    public String getVR() {
+        return tgVR;
+    }
+
+    /**
+     * @param VR the VR to set
+     */
+    public void setVR(String VR) {
+        this.tgVR = VR;
+    }
+
+    /**
+     * @return the VM
+     */
+    public int getVM() {
+        return VM;
+    }
+
+    /**
+     * @param VM the VM to set
+     */
+    public void setVM(int VM) {
+        this.VM = VM;
+    }
+	public void setAlias(String alias) {
+		this.alias = alias;
+	}
+	
+	public void updateTagInformation(TagValue newTag){
+		if(!this.equals(newTag))
+			return;
+		
+		if(newTag.alias != null)
+			this.alias = newTag.alias;
+		
+		if(newTag.name != null)
+			this.name = newTag.name;
+		
+		if(newTag.ret != this.ret)
+			this.ret = newTag.ret;
+		
+		if(this.VM != newTag.VM)
+			this.VM = newTag.VM;
+		
+		if(newTag.tgVR != null)
+			this.tgVR = newTag.tgVR;
+	}
+	
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + tag;
+		return result;
+	}
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		TagValue other = (TagValue) obj;
+		if (tag != other.tag)
+			return false;
+		return true;
+	}
+    
+    public boolean isBinary(){
+    	return this.tgVR.equals("AT");
+    }
+
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagsStruct.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagsStruct.java
new file mode 100755
index 0000000..ca969fc
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/TagsStruct.java
@@ -0,0 +1,469 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.utils;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.collections4.BidiMap;
+import org.apache.commons.collections4.SetUtils;
+import org.apache.commons.collections4.bidimap.DualHashBidiMap;
+
+/**
+ * Structure to manage all the tags inside Dicoogle.
+ * 
+ * There are three groups. DIM Fields, DICOM Fields and PrivateFields
+ * DIM Fields may either be DICOM or Private.
+ * A DICOM and Private groups do not overlap
+ * 
+ * Other fields is the common designation for fields that do not belong to the DIM.
+ *
+ * @author Luís A. Bastião Silva <bastiao at ua.pt>
+ * @author Tiago Marques Godinho <tmgodinho at ua.pt> Refactor
+ */
+public class TagsStruct
+{
+	private static final Logger logger = LoggerFactory.getLogger(TagsStruct.class);
+
+	//Optimization @TODO
+	//Map Structures
+	private BidiMap<Integer, String> tagNameMappings;	
+	private HashMap<Integer, TagValue> tagValueMappings;
+	//Lists (DIM, DICOM, PrivateFields)
+	private Set<TagValue> nDIMFields;
+	private Set<TagValue> nDICOMFields;
+	private Set<TagValue> nPrivateFields;
+	//Modalities
+	private Set<String> modalitiesSet;
+	//Index All Modalities
+    private boolean indexAllModalities = false;
+    //DeepSearch modalities
+    private boolean deepSearchModalities = true;
+    
+    private List<String> dictionaries = new ArrayList<>();
+
+    private static TagsStruct instance = null ;
+
+    public static synchronized TagsStruct getInstance()
+    {
+        if (instance == null) {
+            instance = new TagsStruct();
+        }
+        return instance;
+    }
+
+
+    private TagsStruct()
+    {
+    	//Initialize fields;
+    	this.tagNameMappings = new DualHashBidiMap<>();
+    	this.tagValueMappings = new HashMap<>();
+    	this.nDICOMFields = new HashSet<>();
+    	this.nDIMFields = new HashSet<>();
+    	this.nPrivateFields = new HashSet<>();
+    	this.modalitiesSet = new HashSet<>();
+    	
+    	Map<String, Integer> tmp = DictionaryAccess.getInstance().getTagList();
+    	for(Entry<String, Integer> e : tmp.entrySet()){
+    		addDICOMField(new TagValue(e.getValue(), e.getKey()));
+    	}    	
+    	
+    	addDIMField(new TagValue(Integer.parseInt("1021c0", 16), "PregnancyStatus"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("81050", 16),"PerformingPhysicianName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("400243", 16),"PerformedLocation"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("100020", 16),"PatientID"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80080", 16),"InstitutionName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80050", 16),"AccessionNumber"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80020", 16),"StudyDate"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("102154", 16),"PatientTelephoneNumbers"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("101010", 16),"PatientAge"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("81070", 16),"OperatorName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("200010", 16),"StudyID"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("81040", 16),"InstitutionDepartmentName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("20000e", 16),"SeriesInstanceUID"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("20000d", 16),"StudyInstanceUID"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("100040", 16),"PatientSex"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("201208", 16),"NumberOfStudyRelatedInstances"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("100010", 16),"PatientName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80070", 16),"Manufacturer"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("81090", 16),"ManufacturerModelName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("81030", 16),"StudyDescription"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("700", 16),"Priority"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80090", 16),"ReferringPhysicianName"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80061", 16),"ModalitiesInStudy"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80060", 16),"Modality"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80030", 16),"StudyTime"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80018", 16),"SOPInstanceUID"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80050", 16),"AccessionNumber"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("80070", 16),"Manufacturer"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("700", 16),"Priority"));
+    	addDIMField(new TagValue(
+                 Integer.parseInt("200011", 16),"SeriesNumber"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("08103e", 16),"SeriesDescription"));
+    	addDIMField(new TagValue(
+                Integer.parseInt("100030", 16),"PatientBirthDate"));
+    	
+        addModality("XA");
+        addModality("CT");
+        addModality("US");
+        addModality("MG");
+        addModality("MR");
+    }
+    
+    /**
+     * Adds a new Tag to the structure.
+     * 
+     * @param field
+     */
+    private synchronized void addTag(TagValue field){    	
+    	TagValue tmp = this.tagValueMappings.get(field.getTagNumber());
+    	if(tmp == null){
+    		this.tagNameMappings.put(field.getTagNumber(), field.getName());
+        	this.tagValueMappings.put(field.getTagNumber(), field);    		
+    	}else{
+    		//merge tag information
+    		tmp.updateTagInformation(field);
+    		this.tagNameMappings.put(tmp.getTagNumber(), tmp.getName());
+    	}
+    }
+    
+    /**
+     * Removes a given Tag from the structure
+     * @param field
+     */
+    private synchronized void removeTag(TagValue field){    	
+    	this.tagNameMappings.remove(field.getTagNumber());
+    	this.tagValueMappings.remove(field.getTagNumber());    		
+    }
+    
+    /**
+     * Adds a DIM Field. If the field already exists its information is updated.
+     * @param field
+     */
+    public synchronized void addDIMField(TagValue field){
+    	//this.dimFields.put(field.getTagNumber(), field);
+    	this.nDIMFields.add(field);
+    	if(!isDICOMField(field) && !isPrivateField(field))
+    		addPrivateField(field);
+    	addTag(field);
+    }
+    
+    /**
+     * Adds a private field. Checks if the field is already present in the DICOM fields.
+     * @param field
+     * @return
+     */
+    public synchronized boolean addPrivateField(TagValue field){
+    	addTag(field);
+    	if(this.nDICOMFields.contains(field)){
+    		return true;
+    	}    	
+    	this.nPrivateFields.add(field);
+    	return true;
+    }
+    
+    /**
+     * Removes a Private Field. It is not possible to remove the field if it belongs to the DIM or to the DICOM group.
+     * @param tagNumber
+     * @return
+     */
+    public synchronized boolean removePrivateField(int tagNumber){
+    	//this.dimFields.put(field.getTagNumber(), field);
+    	TagValue tag = this.tagValueMappings.get(tagNumber);
+    	if(this.nDICOMFields.contains(tag)){
+    		return false;
+    	}
+    	
+    	this.nPrivateFields.remove(tag);
+    	this.nDIMFields.remove(tag);
+    	removeTag(tag);
+    	return true;
+    }
+    
+    /**
+     * Adds a DICOM Field.
+     * @param field
+     */
+    private synchronized void addDICOMField(TagValue field){
+    	//this.dimFields.put(field.getTagNumber(), field);
+    	this.nDICOMFields.add(field);
+    	addTag(field);
+    }    
+        
+    /**
+     * Adds a new Modality.
+     * @param modalityName
+     */
+    public void addModality(String modalityName){
+    	this.modalitiesSet.add(modalityName);    	    	
+    }
+    
+    /**
+     * Removes All modalities.
+     */
+    public void removeAllModalities(){
+    	this.modalitiesSet = new HashSet<>();
+    }
+    
+    /**
+     * Removes the specified modality.
+     * @param modality
+     * @return true if the modality was present in the structure.
+     */
+    public boolean removeModality(String modality){
+    	return this.modalitiesSet.remove(modality);
+    }
+    
+    /**
+     * Gets a read-only view of the DIM Fields
+     * @return
+     */
+    public Set<TagValue> getDIMFields(){
+    	return SetUtils.unmodifiableSet(this.nDIMFields);
+    }
+    
+    /**
+     * Gets a List with the DIM fields names.
+     * @return
+     */
+    public ArrayList<String> getDIMTagNames()
+    {
+    	ArrayList<String> tagNames = new ArrayList<>(this.nDIMFields.size());
+    	for(TagValue tag : this.nDIMFields){
+    		tagNames.add(tag.getName());
+    	}
+    	return tagNames;
+    }
+    
+    /**
+     * Gets a List with the DIM fields alias.
+     * @return
+     */
+    public ArrayList<String> getDIMAlias()
+    {
+    	ArrayList<String> alias = new ArrayList<>(this.nDIMFields.size());
+    	for(TagValue tag : this.nDIMFields){
+    		alias.add(tag.getAlias());
+    	}
+    	return alias;
+    }
+    
+    /**
+     * @return a Read-only view of all fields.
+     */
+    public Set<TagValue> getAllFields(){
+    	return SetUtils.unmodifiableSet( new HashSet<>(tagValueMappings.values()) );
+    }
+
+    /**
+     * @return a Read only view of the Private Fields
+     */
+    public Set<TagValue> getPrivateFields(){
+    	return SetUtils.unmodifiableSet(nPrivateFields);
+    }
+    
+    /**
+     * @return the Fields which do not belong to the DIM. (DICOM+Private)
+     */
+    public Set<TagValue> getOtherFields(){
+    	
+    	HashSet<TagValue> tags = new HashSet<>(this.nDICOMFields.size()+this.nPrivateFields.size());
+    	for(TagValue tag : this.tagValueMappings.values()){
+    		if(!isDICOMField(tag))
+    			tags.add(tag);
+    		
+    	}
+    	return tags;
+    }
+    
+    /**
+     * 
+     * @param tagNumber
+     * @return The TagValue object for the given Number, or null.
+     */
+    public TagValue getTagValue(int tagNumber){
+    	return this.tagValueMappings.get(tagNumber);
+    }
+    
+    /**
+     * 
+     * @param tagName
+     * @return The TagValue object for the given its name, or null.
+     */
+    public TagValue getTagValue(String tagName){
+    	Integer x = this.tagNameMappings.getKey(tagName);
+    	if(x == null)
+    		return null;
+    	return this.getTagValue(x);
+    }
+    
+    /**
+     * @param tag
+     * @return Whether the given tag is a DIM Field or not.
+     */
+    public boolean isDIMField(TagValue tag){
+    	return this.nDIMFields.contains(tag);
+    }
+    
+    /**
+     * @param tag
+     * @return Whether the given tag is a DICOM Field or not.
+     */
+    public boolean isDICOMField(TagValue tag){
+    	return this.nDICOMFields.contains(tag);
+    }
+    
+    /**
+     * @param tag
+     * @return Whether the given tag is a Private Field or not.
+     */
+    public boolean isPrivateField(TagValue tag){
+    	return this.nPrivateFields.contains(tag);
+    }
+    
+    /**
+     * @param tag
+     * @return Whether the given tag is an other field or not. (OtherFields = PrivateFields + DICOMFields)
+     */
+    public boolean isOtherField(TagValue tag){
+    	return containsTag(tag.getTagNumber()) && !isDICOMField(tag);
+    }
+    
+    /**
+     * Checks if the tag is present in the structure.
+     * @param tag 
+     * @return 
+     */
+    public boolean containsTag(int tag){
+    	return this.tagValueMappings.containsKey(tag);
+    }
+    
+    /**
+     * Checks if the given modality is present in the structure.
+     * @param modality
+     * @return
+     */
+    public boolean containsModality(String modality){
+    	return this.modalitiesSet.contains(modality);
+    }
+
+    /**
+     * @return a Read-only view of the Modalities.
+     */
+    public Set<String> getModalities() {
+		return SetUtils.unmodifiableSet(modalitiesSet);
+	}
+    
+    /**
+     * Checks if the given modality is Enabled.
+     * @param modality
+     * @return
+     */
+    public boolean isModalityEnable(String modality)
+    {
+    	return isIndexAllModalitiesEnabled() || this.containsModality(modality);
+    }
+
+    /**
+     * @return the indexAllModalities
+     */
+    public boolean isIndexAllModalitiesEnabled() {
+        return indexAllModalities;
+    }
+
+    /**
+     * @param indexAllModalities the indexAllModalities to set
+     */
+    public void enableIndexAllModalities(boolean indexAllModalities) {
+        this.indexAllModalities = indexAllModalities;
+    }
+    
+    public boolean isDeepSearchModalitiesEnabled() {
+		return deepSearchModalities;
+	}
+
+
+	public void enableDeepSearchModalities(boolean deepSearchModalities) {
+		this.deepSearchModalities = deepSearchModalities;
+	}
+
+
+	/**
+     * @return the dictionaries
+     */
+    public List<String> getDictionaries() {
+        return dictionaries;
+    }
+
+    /**
+     * @param dictionaries the dictionaries to set
+     */
+    public void setDictionaries(List<String> dictionaries) {
+        this.dictionaries = dictionaries;
+    }
+    
+    
+    public void addDicionary(String dic)
+    {
+        this.dictionaries.add(dic);
+    }
+    public void removeDicionary(String dic)
+    {
+        this.dictionaries.remove(dic);
+    }
+    
+    
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/package-info.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/package-info.java
new file mode 100644
index 0000000..b5ec387
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Provides many utilities for the Dicoogle programers.
+ * 
+ * @author Tiago Marques Godinho, tmgodinho at ua.pt
+ *
+ */
+package pt.ua.dicoogle.sdk.utils;
\ No newline at end of file
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/ForEachAdapter.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/ForEachAdapter.java
new file mode 100644
index 0000000..f8b3f39
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/ForEachAdapter.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.utils.query;
+
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+
+/**
+ * This interface models the For Each method used in {@link Query}.
+ * 
+ * @see Query
+ * 
+ * @author Tiago Marques Godinho, tmgodinho at ua.pt
+ *
+ */
+public interface ForEachAdapter {
+
+	/**
+	 * This method is executed each time an SearchResult is available.
+	 * @param rs The return result.
+	 */
+	public abstract void forEach(SearchResult rs);
+	
+}
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/Query.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/Query.java
new file mode 100644
index 0000000..e99f9be
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/Query.java
@@ -0,0 +1,160 @@
+/**
+ * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-sdk.
+ *
+ * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package pt.ua.dicoogle.sdk.utils.query;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+
+import pt.ua.dicoogle.sdk.core.DicooglePlatformInterface;
+import pt.ua.dicoogle.sdk.datastructs.SearchResult;
+import pt.ua.dicoogle.sdk.task.JointQueryTask;
+import pt.ua.dicoogle.sdk.task.Task;
+
+/**
+ * This class provides a very easy interface for querying in the Dicoogle.  
+ * Especially in big data scenarios where users should be aware of memory restrictions. 
+ * The usage of an iterative approach is enforced by the adapter. As such, query interface users are not tempted to use the tasks bulk get method.
+ * The query's business logic should be as much encompassed in the adapter as possible.
+ * 
+ * @author Tiago Marques Godinho, tmgodinho at ua.pt
+ *
+ */
+public class Query extends JointQueryTask{
+
+	private DicooglePlatformInterface controller; 
+	
+	private ForEachAdapter adapter;
+	private CountDownLatch latch;
+	
+	/**
+	 * Initializes this helper class.
+	 * 
+	 * @param controller The dicoogle platform proxy.
+	 * @param adapter The adapter holding the business logic of the query.
+	 */
+	public Query(DicooglePlatformInterface controller, ForEachAdapter adapter) {
+		super();
+		this.adapter = adapter;
+		this.controller = controller;
+		this.latch = new CountDownLatch(1);
+	}
+
+	@Override
+	public void onCompletion() {
+		// TODO Auto-generated method stub
+		this.latch.countDown();
+	}
+
+	@Override
+	public void onReceive(Task<Iterable<SearchResult>> e) {
+		
+		Iterable<SearchResult> rs = null;
+		try {
+			rs  = e.get();
+		} catch (InterruptedException | ExecutionException e1) {
+			e1.printStackTrace();
+		}
+		 
+		for(SearchResult r : rs){
+			this.adapter.forEach(r);
+		}
+	}
+	
+	/**
+	 * Awaits for the query to finish.
+	 */
+	public void await() {
+		try {
+			latch.await();
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * This method provides the same interface as the Dicoogle Platform Interface.
+	 * The await method is called after the query is performed. So this is a blocking method.
+	 * 
+	 * @see DicooglePlatformInterface
+	 * 
+	 * @param query Query String
+	 * @param parameters Parameters
+	 */
+	public void queryAll(String query,
+			Object... parameters){			
+		@SuppressWarnings("unused")
+		JointQueryTask task = controller.queryAll(this, query, parameters);
+		await();
+	}
+
+	/**
+	 * This method provides the same interface as the Dicoogle Platform Interface.
+	 * The await method is called after the query is performed. So this is a blocking method.
+	 * 
+	 * @see DicooglePlatformInterface
+	 * 
+	 * @param querySource The query plugin's name
+	 * @param query Query String
+	 * @param parameters Parameters
+	 */
+	public void query(String querySource,
+			String query, Object... parameters) {
+		List<String> querySources = new ArrayList<String>(1);
+		querySources.add(querySource);
+		
+		this.query(querySources, query, parameters);
+	}
+
+	/**
+	 * This method provides the same interface as the Dicoogle Platform Interface.
+	 * The await method is called after the query is performed. So this is a blocking method.
+	 * 
+	 * @see DicooglePlatformInterface
+	 * 
+	 * @param querySources A List holding the queries plugin's names that should handle the query.
+	 * @param query Query String
+	 * @param parameters Parameters
+	 */
+	public void query(List<String> querySources, String query, Object... parameters) {			
+		@SuppressWarnings("unused")
+		JointQueryTask task = controller.query(this, querySources, query, parameters);
+		
+		await();
+	}
+	
+	/**
+	 * Sets the Dicoogle Platform Controller.
+	 * @param controller The new controller.
+	 */
+	public void setController(DicooglePlatformInterface controller) {
+		this.controller = controller;
+	}
+
+	/**
+	 * Sets the for each adapter.
+	 * 
+	 * @param adapter The adapter.
+	 */
+	public void setAdapter(ForEachAdapter adapter) {
+		this.adapter = adapter;
+	}
+}
\ No newline at end of file
diff --git a/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/package-info.java b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/package-info.java
new file mode 100644
index 0000000..112e138
--- /dev/null
+++ b/sdk/src/main/java/pt/ua/dicoogle/sdk/utils/query/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Utilities which may be used during the query process.
+ * 
+ * @author Tiago Marques Godinho, tmgodinho at ua.pt
+ *
+ */
+package pt.ua.dicoogle.sdk.utils.query;
\ No newline at end of file
diff --git a/short-license.txt b/short-license.txt
new file mode 100644
index 0000000..23158a0
--- /dev/null
+++ b/short-license.txt
@@ -0,0 +1,16 @@
+Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+
+This file is part of Dicoogle/${project.name}.
+
+Dicoogle/${project.name} is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Dicoogle/${project.name} is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/webcore/.eslintrc b/webcore/.eslintrc
new file mode 100644
index 0000000..2c5e397
--- /dev/null
+++ b/webcore/.eslintrc
@@ -0,0 +1,43 @@
+{
+  "extends": [
+    "eslint:recommended",
+    "plugin:import/errors",
+    "plugin:import/warnings"
+  ],
+  "parserOptions": {
+    "ecmaVersion": 6,
+    "sourceType": "module",
+    "ecmaFeatures": {
+      "modules": true
+    }
+  },
+  "env": {
+    "browser": true,
+    "commonjs": true,
+    "es6": true
+  },
+  "plugins": [ "import" ],
+  "globals": {
+    "process": false
+  },
+  "rules": {
+    "no-console": 0,
+    "quotes": 0,
+    "curly": 0,
+    "new-cap": 0,
+    "camelcase": 0,
+    "no-unused-vars": 0,
+    "comma-dangle": 1,
+    "no-extra-semi": 1,
+    "key-spacing": 1,
+    "semi-spacing": 1,
+    "eol-last": 1,
+    "valid-jsdoc": 1,
+    "no-undef": 2,
+    "import/no-unresolved": [2, {"commonjs": true}],
+    "import/named": 2,
+    "import/namespace": 2,
+    "import/default": 2,
+    "import/export": 2
+  }
+}
diff --git a/webcore/README.md b/webcore/README.md
new file mode 100644
index 0000000..59c67bb
--- /dev/null
+++ b/webcore/README.md
@@ -0,0 +1,226 @@
+# Dicoogle Web Core
+
+This JavaScript project aims to provide the backbone for Dicoogle Web UI plugins.
+The essence of this architecture is that Dicoogle web pages will contain stub slots where plugins can be attached to.
+
+## Building and Using
+
+> Note: These details are only relevant to developers of Dicoogle and its web app. To learn how to develop web UI plugins, please skip this section.
+
+The project can be built by calling `npm install`. On Dicoogle, simply install `dicoogle-webcore` as a dependency and `import` (or `require`) the package module. Then:
+
+ - Place `<dicoogle-slot>` elements in the page. They must contain a unique slot id attribute `data-slot-id`.
+ - Invoke the module's `init()` to initialize the module. It will automatically detect slots, as well as fetch and attach plugins. This method
+   should only be called once. New slots attached dynamically will be automatically filled.
+ - In order to know what menu plugins are available, invoke `fetchPlugins('menu'[, callback])`.
+
+The optional web component attribute `data-plugin-name` can be passed to the `<dicoogle-slot>` in order to retrieve a specific plugin (rather than all compatible plugins for that slot).
+
+Furthermore, slot elements will emit a `plugin-load` custom event (not to be confused with the webcore's event emitter) each time a specific plugin is created and rendered. The event can be listened by adding a typical DOM event listener:
+
+```javascript
+slotElement.addEventListener('plugin-load', fnHandleEvent);
+```
+
+The `detail` property of the event will contain the object returned by the render method. In Dicoogle, this can be used for attaching React elements without rendering directly to the DOM.
+
+Plugin web components will be attached to a div in the `<dicoogle-slot>` with its class defined as
+`"dicoogle-webcore-<slotid>-instance"` (e.g. `"dicoogle-webcore-query-instance"`). The div of these parents
+will have a class `"dicoogle-webcore-<slotid>"`. The Dicoogle web application may use these classes to style these
+additional UI elements.
+
+A few examples of web pages using the Dicoogle Web Core are available in "test/TC".
+
+### Runtime Dependencies
+
+Dicoogle Web Core requires HTML custom element support.
+Include the "document-register-elements" script in order to extend HTML5 custom element support to other browsers.
+
+## Creating plugins
+
+You can create your own plugins by providing a directory containing two essential files: a plugin descriptor and a JavaScript module.
+
+### Plugin descriptor
+
+A descriptor takes the form of a "package.json", an `npm` package descriptor, containing at least these attributes:
+
+ - `name` : the unique name of the plugin (must be compliant with npm)
+ - `version` : the version of the plugin (must be compliant with npm)
+ - `description` _(optional)_ : a simple, one-line description of the package
+ - `dicoogle` : an object containing Dicoogle-specific information:
+      - `caption` _(optional, defaults to name)_ : an appropriate title for being shown as a tab (or similar) on the web page
+      - `slot-id` : the unique ID of the slot where this plugin is meant to be attached
+      - `module-file` _(optional, defaults to "module.js")_ : the name of the file containing the JavaScript module
+
+
+In addition, these attributes are recommended:
+
+  - `author` : the author of the plugin
+  - `tags` : the tags "dicoogle" and "dicoogle-plugin" are recommended
+  - `private` : if you do not intend to publish the plugin into an npm repository, set this to `true`.
+
+An example of a valid "package.json":
+
+```json
+{
+  "name" : "dicoogle-cbir-query",
+  "version" : "0.0.1",
+  "description" : "CBIR Query-By-Example plugin",
+  "author": "John Doe <jdoe at somewhere.net>",
+  "tags": ["dicoogle", "dicoogle-plugin"],
+  "dicoogle" : {
+    "caption" : "Query by Example",
+    "slot-id" : "query",
+    "module-file" : "module.js"
+  }
+}
+```
+
+### Module
+
+In addition, a JavaScript module must be implemented, containing the entire logic and rendering of the plugin.
+The final module script must be exported in CommonJS format (similar to the Node.js module standard), or using
+the ECMAScript Harmony import/export notation (as in ES2015) when transpiled with Babel.
+The developer may also choose to create the module under the UMD format, although this is not required. The developer
+can make multiple node-flavored CommonJS modules and use tools like browserify to bundle them and embed dependencies.
+Some of those however, can be required without embedding: "react" and "dicoogle-client" can be retrieved via `require`
+and must be marked as external dependencies.
+
+The exported module must be a single constructor function (or class), in which instances must have a `render(parent, slot)` method:
+
+```javascript
+/** Render and attach the contents of a new plugin instance to the given DOM element.
+ * @param {DOMElement} parent the parent element of the plugin component
+ * @param {DOMElement} slot the DOM element of the Dicoogle slot
+ * @return Alternatively, return a React element while leaving `parent` intact. (Experimental, still unstable!)
+ */
+function render(parent, slot) {
+    // ...
+}
+```
+
+Furthermore, the `onResult` method must be implemented if the plugin is for a "result" slot:
+
+```javascript
+/** Handle result retrieval here by rendering them.
+ * @param {object} results an object containing the results retrieved from Dicoogle's search service 
+ */
+function onResult(results) {
+    // ...
+}
+```
+
+All modules will have access to the `Dicoogle` plugin-local alias for interfacing with Dicoogle.
+Query plugins can invoke `issueQuery(...)` to perform a query and expose the results on the page (via result plugins).
+Other REST services exposed by Dicoogle are easily accessible with `request(...)`.
+See the [Dicoogle JavaScript client package](https://github.com/bioinformatics-ua/dicoogle-client-js) and the Dicoogle
+Web API section below for a more thorough documentation.
+
+Modules are meant to work independently, but can have embedded libraries if so is desired. In
+addition, if the underlying web page is known to contain specific libraries, then these can also be used without being
+embedded. This is particularly useful to avoid replicating dependencies and prevent modules from being too large.
+
+Below is an example of a plugin module.
+
+```javascript
+module.exports = function() {
+
+  // ...
+
+  this.render = function(parent, slot) {
+    var e = document.create('span');
+    e.innerHTML = 'Hello Dicoogle!';
+    parent.appendChild(e);
+  };
+};
+```
+
+Exporting a class in ECMAScript 6 also works (since classes are syntatic sugar for ES5 constructors).
+The code below can be converted to ES5 using Babel:
+
+```javascript
+export default class MyPluginModule() {
+
+  render(parent) {
+    let e = document.create('span');
+    e.innerHTML = 'Hello Dicoogle!';
+    parent.appendChild(e);
+  }
+};
+```
+
+### Dicoogle Web API
+
+Either `require` the `dicoogle-client` module (if the page supports the operation) or use the alias `Dicoogle` to 
+access and perform operations on Dicoogle and the page's web core. All methods described in
+[`dicoogle-client`](https://github.com/bioinformatics-ua/dicoogle-client-js) are available. Furthermore, the web
+core injects the following methods:
+
+#### **issueQuery** : `function(query, options, callback)`
+
+Issue a query to the system. This operation is asynchronous and will automatically issue back a result exposal to the
+page's result module. The query service requested will be "search" unless modified with the _overrideService_ option.
+
+ - _query_ an object or string containing the query to perform
+ - _options_ an object containing additional options (such as query plugins to use, result limit, etc.)
+     - \[_overrideService_\] {string} the name of the service to use instead of "search"
+ - _callback_ an optional callback function(error, result)
+
+####  **addEventListener** : `function(eventName, fn)`
+
+Add an event listener to an event triggered by the web core.
+
+ - _eventName_ : the name of the event (can be one of 'load','menu' or a custom one)
+ - _fn_ : a callback function (arguments vary) -- `function(...)`
+
+#### **addResultListener** : `function(fn)`
+
+Add a listener to the 'result' event, triggered when a query result is obtained.
+
+ - _fn_ : `function(result, requestTime, options)`
+
+#### **addPluginLoadListener** : `function(fn)`
+
+Add a listener to the 'load' event, triggered when a plugin is loaded.
+
+ - _fn_ : `function(Object{name, slotId, caption})`
+
+#### **addMenuPluginListener** : `function(fn)`
+
+Add a listener to the 'menu' event, triggered when a menu plugin descriptor is retrieved.
+This may be useful for a web page to react to retrievals by automatically adding menu entries.
+
+ - _fn_ : `function(Object{name, slotId, caption})`
+
+#### **emit**: `function(eventName, ...args)`
+
+Emit an event through the webcore's event emitter.
+
+ - _eventName_ : the name of the event
+ - _args_ : variable list of arguments to be passed to the listeners
+
+#### **emitSlotSignal**: `function(slotDOM, eventName, data)`
+
+Emit a DOM custom event from the slot element.
+
+ - _slotDOM_ : the slot DOM element to emit the event from
+ - _name_ : the event name
+ - _data_ : the data to be transmitted as custom event detail
+
+### Webcore Events
+
+Full list of events that can be used by plugins and the webapp. _(Work in Progress)_
+
+ - "load" : Emitted when a plugin package is retrieved.
+ - "result" : Emitted when a list of search results is obtained from the search interface.
+
+## Installing Plugins
+
+Place all contents of a plugin in a directory and insert the directory (by copying or linking)
+into the "WebPlugins" folder at the base working directory. Alternatively, package a "WebPlugins"
+directory with the same contents in a Dicoogle plugin jar. All plugins will then be retrieved the
+next time the Dicoogle server loads.
+
+## Testing Plugins
+
+Web UI plugins can be tested by deploying them into Dicoogle.
diff --git a/webcore/package.json b/webcore/package.json
new file mode 100644
index 0000000..5e3e537
--- /dev/null
+++ b/webcore/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "dicoogle-webcore",
+  "version": "0.14.0",
+  "private": true,
+  "author": "Universidade de Aveiro, DETI/IEETA, Bioinformatics Group (http://bioinformatics.ua.pt/)",
+  "maintainers": [
+    "Eduardo Pinho <eduardopinho at ua.pt>"
+  ],
+  "contributors": [
+    "Eduardo Pinho <eduardopinho at ua.pt>",
+    "Luís Bastião Silva <bastiao at bmd-software.com>"
+  ],
+  "description": "Dicoogle Web Core for UI plugins",
+  "files": [
+    "src/*.js"
+  ],
+  "jsnext:main": "src/dicoogle-webcore.js",
+  "main": "src/dicoogle-webcore.js",
+  "browserify": {
+    "transform": [["babelify", { "presets": ["es2015"] }]]
+  },
+  "keywords": [
+    "dicoogle"
+  ],
+  "scripts": {
+    "check": "eslint src"
+  },
+  "license": "GPL-3.0+",
+  "devDependencies": {
+    "eslint": "^2.11.1",
+    "eslint-plugin-import": "^1.8.1"
+  },
+  "peerDependencies": {
+    "dicoogle-client": "^3.6.0"
+  },
+  "dependencies": {
+    "document-register-element": "^0.5.4",
+    "events": "^1.1.0"
+  }
+}
diff --git a/webcore/src/dicoogle-webcore.js b/webcore/src/dicoogle-webcore.js
new file mode 100644
index 0000000..f7d8fcd
--- /dev/null
+++ b/webcore/src/dicoogle-webcore.js
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2015  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
+ *
+ * This file is part of Dicoogle/dicoogle-webcore.
+ *
+ * Dicoogle/dicoogle-webcore is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Dicoogle/dicoogle-webcore is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import {EventEmitter} from 'events';
+import client from 'dicoogle-client';
+require('document-register-element');
+
+/** Dicoogle web application core.
+ * This module provides support to web interface plugins.
+ */
+const DicoogleWebcore = (function () {
+  var m = { constructors: {} };
+  
+  // hidden properties
+  
+  var slots = {}; // [slotId:string]: WebUiSlot
+  var plugins = {}; // [name:string]:Constructor
+  var packages = {}; // [name:string]:JSONPackage
+  var base_url = null;
+  var Dicoogle; // eslint-disable-line no-unused-vars
+  var event_hub = null;
+
+  const EVENT_NAMES = Object.freeze([ // eslint-disable-line no-unused-vars
+    'load',
+    'menu',
+    'loadMenu',
+    'loadQuery',
+    'loadResult',
+    'result'
+  ]);
+  
+  // development-time checker
+  function check_initialized() {
+      if (base_url === null) {
+          console.error('Dicoogle Webcore has not been initialized! Please call the init method.');
+          return false;
+      }
+      return true;
+  }
+
+  /** Initialize Dicoogle Webcore. This should be called once and at the beginning
+   * of the web page's life time.
+   * @param {string} baseURL the base URL to the Dicoogle services
+   * @return {void}
+   */
+  m.init = function(baseURL) {
+    if (typeof document !== 'object') {
+      throw "no DOM environment!";
+    }
+    console.log('Initializing Dicoogle web core ...');
+    if (typeof baseURL === 'string') {
+      base_url = baseURL;
+      if (base_url[base_url.length-1] === '/') {
+        base_url = base_url.slice(0, -1);
+      }
+    }
+    slots = {};
+    plugins = {};
+    packages = {};
+    event_hub = new EventEmitter();
+    
+    // create dicoogle client access object
+    // and inject webcore related methods
+    Dicoogle = client(base_url);
+    Object.assign(Dicoogle, {
+        issueQuery,
+        emit,
+        emitSlotSignal,
+        addMenuPluginListener: m.addMenuPluginListener,
+        addPluginLoadListener: m.addPluginLoadListener,
+        addEventListener: m.addEventListener,
+        addResultListener: m.addResultListener,
+        removeEventListener: m.removeEventListener
+    });
+    
+  };
+  
+  /** Emit an event from the webcore's event emitter.
+   * @param {string} name the event name
+   * @param {...any} args the data to be transmitted as function arguments to the listeners
+   * @return {void}
+   */
+  function emit(name, ...args) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.emit(name, ...args);
+  }
+
+  /** Emit a DOM custom event from the slot element.
+   * @param {HTMLDicoogleSlotElement} slotDOM the slot DOM element to emit the event from
+   * @param {string} name the event name
+   * @param {any} data the data to be transmitted as custom event detail
+   * @return {void}
+   */
+  function emitSlotSignal(slotDOM, name, data) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    slotDOM.dispatchEvent(new CustomEvent(name, {detail: data}));
+  }
+  
+  /** Add an event listener to the webcore's event emitter.
+   * @param {string} eventName the name of the event (can be one of 'load','loadMenu','loadQuery','loadResult', or custom event names)
+   * @param {function(...any)} fn the listener function
+   * @return {DicoogleWebcore} the webcore module itself, used for chaining
+   */
+  m.addEventListener = function(eventName, fn) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.on(eventName, fn);
+    return m;
+  };
+
+  /** Remove an event listener from the webcore's event emitter.
+   * @param {string} eventName the name of the event
+   * @param {function(...any)} fn the listener function
+   * @return {DicoogleWebcore} the webcore module itself, used for chaining
+   */
+  m.removeEventListener = function(eventName, fn) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.removeListener(eventName, fn);
+    return m;
+  };
+  
+  /**@typedef {object} PluginDesc
+   * @property {string} name the unique name of the plugin
+   * @property {string} slotId the slot ID that must be attached to
+   * @property {?string} caption a caption for the plugin
+   */
+  
+  /** Add a listener to the 'result' event
+   * @param {function(result, requestTime, options)} fn the listener function
+   * @return {DicoogleWebcore} the webcore module itself, used for chaining
+   */
+  m.addResultListener = function (fn) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.on('result', fn);
+    return m;
+  };
+  
+  /** Add a listener to the 'load' event
+   * @param {function(PluginDesc)} fn the listener function
+   * @return {DicoogleWebcore} the webcore module itself, used for chaining
+   */
+  m.addPluginLoadListener = function (fn) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.on('load', fn);
+  };
+
+  /** Add a listener to the 'menu' event
+   * @param {function(PluginDesc)} fn the listener function
+   * @return {DicoogleWebcore} the webcore module itself, used for chaining
+   */
+  m.addMenuPluginListener = function (fn) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    event_hub.on('menu', fn);
+  };
+    
+  m.updateSlots = function() {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    if (typeof document !== 'object') {
+      throw "no DOM environment!";
+    }
+    
+    if (base_url === null) {
+      return;
+    }
+    
+    // take all <dicoogle-slot> elements in page
+    let slotsDOM = document.getElementsByTagName('dicoogle-slot');
+    for (let i = 0; i < slotsDOM.length; i++) {
+      m.loadSlot(slotsDOM[i]);
+    }
+    
+    // finally, fetch the needed plugins and load each one of them
+    let slotIds = Object.keys(slots);
+    //if (Object.keys(plugins).length !== slotIds.length) {
+    m.fetchPlugins(slotIds, function(packages) {
+      for (let i = 0; i < packages.length; i++) {
+        load_plugin(packages[i]);
+      }
+    });
+    //}
+  };
+
+  /** Update a given slot.
+   * @param {HTMLDicoogleSlotElement} elem the Dicoogle slot DOM element
+   * @param {function()} callback called once per plugin
+   * @return {void}
+   */
+  m.updateSlot = function(elem, callback) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    if (typeof document !== 'object') {
+      throw "no DOM environment!";
+    }
+    
+    loadSlot(elem);
+
+    // check for plugins of this slotId
+    const pluginsOfSlot = getPluginsOf(elem.slotId);
+    if (pluginsOfSlot.length > 0) {
+      // we already have the plugins, attach them
+      m.attachAllPlugins(elem);
+    } else {
+      // fetch the needed plugins and load them
+      m.fetchPlugins(elem.slotId, function(packages) {
+        for (let i = 0; i < packages.length; i++) {
+          load_plugin(packages[i], callback);
+        }
+      });
+    }
+  };
+    
+  /** Fetch the plugin information from the server.
+   * @param {string|string[]} slotIds a slot id name or an array of slot id's
+   * @param {function(object[])} [callback] a callback function
+   * @return {void}
+   */
+  m.fetchPlugins = function (slotIds, callback) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    console.log('Fetching Dicoogle web UI plugin descriptors ...');
+    slotIds = [].concat(slotIds);
+    let uri = 'webui';
+    service_get(uri, {'slot-id': slotIds}, function(error, data) {
+      if (error) {
+        console.error('Failed to fetch plugin descriptors:' , error);
+        return;
+      }
+      var packageArray = data.plugins;
+      for (let i = 0; i < packageArray.length; i++) {
+        if (!packages[packageArray[i].name]) {
+          packages[packageArray[i].name] = packageArray[i];
+          if (packageArray[i].dicoogle.slotId === 'menu') {
+            event_hub.emit('menu', {name: packageArray[i].name, slotId: 'menu', caption: packageArray[i].dicoogle.caption});
+          }
+        }
+      }
+      if (callback) {
+        callback(packageArray);
+      }
+    });
+  };
+
+  /** Issue that the JavaScript modules are loaded, even if no slot has requested it.
+   * This function is asynchronous, but currently provides no callback.
+   * @param {PackageJSON|PackageJSON[]} packages the JSON package descriptors
+   * @return {void}
+   */
+  m.fetchModules = function(packages) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    packages = [].concat(packages);
+    for (let i = 0; i < packages.length; i++) {
+      if (!(packages[i].name in plugins)) {
+        load_plugin(packages[i]);
+      }
+    }
+  };
+      
+  // --------------------- Injected Plugin-accessible methods ----------------------------
+  
+  /** Issue a query to the system. This operation is asynchronous
+   * and will automatically issue back a result exposal. The query service requested will be "search" unless modified
+   * with the overrideService option.
+   * function(query, options, callback)
+   * @param {any} query an object containing the query (usually a string)
+   * @param {object} options an object containing additional options (such as query plugins to use, result limit, etc.)
+   *      - overrideService [string] the name of the service to use instead of "search" 
+   * @param {function(error, result)} callback an optional callback function
+   * @return {void}
+   */
+  function issueQuery(query, options, callback) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    options = options || {};
+    options.query = query;
+    let requestTime = new Date();
+    let queryService = options.overrideService || 'search';
+    service_get(queryService, options, function (error, data) {
+      if (error) {
+        if (callback) callback(error, null);
+        return;
+      }
+      dispatch_result(data, requestTime, options);
+      if (callback) callback(null, data);
+    });
+  }
+  
+  /** Invoked by the webUI service for registering a new plugin implementation.
+   * @param {{render:function}} pluginInstance a module describing a plugin
+   * @param {string} name the name of the plugin
+   * @return {void}
+   */
+  m.onRegister = function(pluginInstance, name) {
+    console.log('onRegister', pluginInstance);
+    if (plugins[name]) {
+        // already registered, ignore
+        return;
+    }
+    
+    if (typeof pluginInstance !== 'object' || typeof pluginInstance.render !== 'function') {
+      console.error('Dicoogle web UI plugin ', name, ' is corrupted or invalid: ', pluginInstance);
+      return;
+    }
+    let thisPackage = packages[name];
+    let slotId = thisPackage.dicoogle['slot-id'];
+    if (slotId === 'result' && typeof pluginInstance.onResult !== 'function') {
+      console.error('Dicoogle web UI plugin ', name, ' does not provide onResult');
+      return;
+    }
+    console.log('Executed plugin: ', name);
+    pluginInstance.Name = name;
+    pluginInstance.SlotId = slotId;
+    pluginInstance.Caption = thisPackage.dicoogle.caption || name;
+    plugins[name] = pluginInstance;
+    if (slots[slotId]) {
+      for (let slot of slots[slotId]) {
+        slot.attachPlugin(pluginInstance);
+      }
+    }
+    const eventData = {name, slotId, caption: pluginInstance.Caption};
+    event_hub.emit('load', eventData);
+  };
+  
+  /** Attach all discovered plugins to the given compatible slot if compatible.
+   * @param {HTMLDicoogleSlotElement} elem the slot element
+   * @return {void}
+   */
+  m.attachAllPlugins = function(elem) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    getPluginsOf(elem.slotId).forEach(pluginInstance => {
+      elem.webUi.attachPlugin(pluginInstance);
+    });
+  };
+
+  // ----------------------------------------------------------------------------
+  m.WebUISlot = function(id, dom) {
+    this.id = id;
+    this.dom = dom;
+    this.pluginName = dom.pluginName;
+    this.attachments = [];
+    this.dom.className = 'dicoogle-webcore-' + this.id;
+    this.dom.webUi = this;
+    
+    this.attachPlugin = function(plugin) {
+      if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+      if (plugin.SlotId !== this.id) {
+        console.error(`Attempt to attach plugin ${plugin.Name} to the wrong slot`);
+        return;
+      }
+      if ((typeof this.pluginName === 'string') && this.pluginName !== plugin.Name) {
+        //console.log('Ignoring plugin', plugin.Name);
+        return;
+      }
+      if (this.attachments.length === 0) {
+        this.dom.innerHTML = '';
+      }
+      let pluginDOM = document.createElement('div');
+      pluginDOM.className = this.dom.className + '-instance';
+      this.dom.appendChild(pluginDOM);
+      const e = plugin.render(pluginDOM, this.dom);
+      
+      emitSlotSignal(dom, 'plugin-load', e);
+      
+      this.attachments.push(plugin);
+      plugin.TabIndex = this.attachments.length - 1;
+      plugin.Slot = this; // provide slot object
+    };
+
+    this.refresh = function() {
+      if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+      let slotDOM = this.dom;
+      slotDOM.innerHTML = '';
+      for (let i = 0; i < this.attachments.length; i++) {
+        let pluginDOM = document.createElement('div');
+        pluginDOM.className = slotDOM.className + '-instance';
+        slotDOM.appendChild(pluginDOM);
+        this.attachments[i].render(pluginDOM);
+      }
+    };
+  };
+
+  // ---------------- private methods ----------------
+  const ostring = Object.prototype.toString;
+  function isArray(it) {
+    return ostring.call(it) === '[object Array]';
+  }
+  
+  function isFunction(it) {
+    return ostring.call(it) === '[object Function]';
+  }
+
+  /** Load a new Dicoogle slot into the core.
+   * @param {HTMLDicoogleSlotElement} slotDOM a DOM element in the document with the correct tag name
+   * @return {string} the id of the slot
+   */
+  function loadSlot (slotDOM) {
+    if (base_url === null) {
+      return;
+    }
+    if (!slotDOM.slotId) {
+      console.error('Dicoogle web UI slot has no data-slot-id attribute!');
+      return null;
+    }
+    let id = slotDOM.slotId;
+    if (!slots[id]) {
+        slots[id] = [];
+    }
+    slots[id].push(new m.WebUISlot(id, slotDOM));
+    console.log('Created new Dicoogle ' + id + ' slot');
+    return id;
+  }
+
+  function load_plugin(packageJSON, callback) {
+    console.log('Loading plugin', packageJSON.name);
+    const {name} = packageJSON;
+    if (plugins[name]) {
+        if (callback) callback(plugins[name]);
+    } else {
+        getScript(packageJSON.name, function() {
+          console.log('Loaded module ', name);
+          if (!isFunction(m.constructors[name])) {
+             console.error(`The loaded module ${name} is not a function!`);
+          }
+          if (callback) callback(plugins[name]);
+        });
+    }
+  }
+  
+  function getPluginsOf(slotId) {
+    if (process.env.NODE_ENV !== 'production' && !check_initialized()) return;
+    const pluginsOfSlot = [];
+    if (plugins) {
+      for (let name in plugins) {
+        if (plugins[name].SlotId === slotId) {
+            pluginsOfSlot.push(plugins[name]);
+        }
+      }
+    }
+    return pluginsOfSlot;
+  }
+    
+  function dispatch_result(result, requestTime, options) {
+    var resultSlotArray = slots.result;
+    if (!resultSlotArray) {
+      console.error('Cannot show results without a result slot.');
+      return;
+    }
+    for (const resultSlot of resultSlotArray) {
+      for (let i = 0; i < resultSlot.attachments.length; i++) {
+        resultSlot.attachments[i].onResult(result, requestTime, options);
+      }
+    }
+    event_hub.emit('result', result, requestTime, options);
+  }
+  
+  /**
+   * Send a GET request to a Dicoogle service.
+   *
+   * @param {string} uri the request URI in string or array form
+   * @param {string} qs an object containing query string parameters (or a QS without '?')
+   * @param {function(error, outcome)} callback a callback function
+   * @return {void}
+   */
+  function service_get(uri, qs, callback) {
+    // issue request
+    //const full_uri = [base_url].concat(uri);
+    //request('GET', full_uri, qs, callback);
+    Dicoogle.request('GET', uri, qs, callback);
+  }
+  
+  function getScript(moduleName, callback) {
+    let script = document.createElement('script');
+    let prior = document.getElementsByTagName('script')[0];
+    
+    script.async = true;
+    let onLoadHandler = function( _, isAbort ) {
+        if(isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
+            script.onload = script.onreadystatechange = null;
+            script = undefined;
+            if(!isAbort) {
+              if(callback) callback();
+            }
+        }
+    };
+    script.onload = script.onreadystatechange = onLoadHandler;
+    script.src = base_url+'/webui/module/'+moduleName;
+    prior.parentNode.insertBefore(script, prior);
+  }
+
+  // custom element definitions
+  var HTMLDicoogleSlotElement = (function() {
+    var elem = document.registerElement('dicoogle-slot', {
+      prototype: Object.create(HTMLDivElement.prototype, {
+        slotId: {
+          get () {
+            return this.getAttribute('data-slot-id');
+          }
+        },
+        pluginName: {
+          get () {
+            return this.getAttribute('data-plugin-name');
+          }
+        },
+        webUi: {
+          get () {
+            return this._webUi;
+          },
+          set (webUi) {
+            this._webUi = webUi;
+          }
+        },
+        createdCallback: { value () {
+        }},
+        attachedCallback: { value () {
+          console.log('[CALLBACK] Dicoogle slot attached: ', this);
+          const attSlotId = this.attributes['data-slot-id'];
+          if (!attSlotId || !attSlotId.value || attSlotId === '') {
+            console.error('Dicoogle slot contains illegal data-slot-id!');
+            return;
+          }
+
+          // add content if the webcore plugin is already available
+          if (base_url !== null) {
+            m.updateSlot(this, pluginInstance => {
+            });
+          }
+          //console.log('[CALLBACK] Dicoogle slot attached: ', this);
+        }},
+        detachedCallback: { value () {
+          //console.log('[CALLBACK] Dicoogle slot detached: ', this);
+          const typedSlots = slots[this.slotId];
+          for (let i = 0; i < typedSlots.length; i++) {
+            if (typedSlots[i].slotDOM === this) {
+                typedSlots.splice(i, 1);
+                break;
+            }
+          }
+        }},
+        attributeChangedCallback: { value (attrName, oldVal, newVal) {
+          // console.log('[CALLBACK] Dicoogle attribute changed');
+          if (attrName === 'data-slot-id' || attrName === 'data-plugin-name') {
+            m.updateSlot(this);
+          }
+        }}
+      })
+    });
+    console.log('Registered HTMLDicoogleSlotElement');
+    return elem;
+  })();
+
+  m.HTMLDicoogleSlotElement = HTMLDicoogleSlotElement;
+  
+  return m;
+})();
+
+export default DicoogleWebcore;
diff --git a/webcore/src/jsconfig.json b/webcore/src/jsconfig.json
new file mode 100644
index 0000000..8825352
--- /dev/null
+++ b/webcore/src/jsconfig.json
@@ -0,0 +1,6 @@
+{
+	"compilerOptions": {
+		"target": "ES6",
+		"module": "commonjs"
+	}
+}
diff --git a/webcore/test/TC/document-register-element.js b/webcore/test/TC/document-register-element.js
new file mode 100644
index 0000000..3ea1445
--- /dev/null
+++ b/webcore/test/TC/document-register-element.js
@@ -0,0 +1,2 @@
+/*! (C) WebReflection Mit Style License */
+(function(e,t,n,r){"use strict";function et(e,t){for(var n=0,r=e.length;n<r;n++)ct(e[n],t)}function tt(e){for(var t=0,n=e.length,r;t<n;t++)r=e[t],Z(r,b[rt(r)])}function nt(e){return function(t){j(t)&&(ct(t,e),et(t.querySelectorAll(w),e))}}function rt(e){var t=e.getAttribute("is"),n=e.nodeName.toUpperCase(),r=S.call(y,t?v+t.toUpperCase():d+n);return t&&-1<r&&!it(n,t)?-1:r}function it(e,t){return-1<w.indexOf(e+'[is="'+t+'"]')}function st(e){var t=e.currentTarget,n=e.attrChange,r=e.prevValu [...]
\ No newline at end of file
diff --git a/webcore/test/TC/react-0.13.0.js b/webcore/test/TC/react-0.13.0.js
new file mode 100644
index 0000000..50c578f
--- /dev/null
+++ b/webcore/test/TC/react-0.13.0.js
@@ -0,0 +1,19535 @@
+/**
+ * React v0.13.0
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define('react',[],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.React = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0 [...]
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule React
+ */
+
+/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/
+
+'use strict';
+
+var EventPluginUtils = _dereq_(19);
+var ReactChildren = _dereq_(32);
+var ReactComponent = _dereq_(34);
+var ReactClass = _dereq_(33);
+var ReactContext = _dereq_(38);
+var ReactCurrentOwner = _dereq_(39);
+var ReactElement = _dereq_(57);
+var ReactElementValidator = _dereq_(58);
+var ReactDOM = _dereq_(40);
+var ReactDOMTextComponent = _dereq_(51);
+var ReactDefaultInjection = _dereq_(54);
+var ReactInstanceHandles = _dereq_(66);
+var ReactMount = _dereq_(70);
+var ReactPerf = _dereq_(75);
+var ReactPropTypes = _dereq_(78);
+var ReactReconciler = _dereq_(81);
+var ReactServerRendering = _dereq_(84);
+
+var assign = _dereq_(27);
+var findDOMNode = _dereq_(117);
+var onlyChild = _dereq_(144);
+
+ReactDefaultInjection.inject();
+
+var createElement = ReactElement.createElement;
+var createFactory = ReactElement.createFactory;
+var cloneElement = ReactElement.cloneElement;
+
+if ("production" !== "development") {
+  createElement = ReactElementValidator.createElement;
+  createFactory = ReactElementValidator.createFactory;
+  cloneElement = ReactElementValidator.cloneElement;
+}
+
+var render = ReactPerf.measure('React', 'render', ReactMount.render);
+
+var React = {
+  Children: {
+    map: ReactChildren.map,
+    forEach: ReactChildren.forEach,
+    count: ReactChildren.count,
+    only: onlyChild
+  },
+  Component: ReactComponent,
+  DOM: ReactDOM,
+  PropTypes: ReactPropTypes,
+  initializeTouchEvents: function(shouldUseTouch) {
+    EventPluginUtils.useTouchEvents = shouldUseTouch;
+  },
+  createClass: ReactClass.createClass,
+  createElement: createElement,
+  cloneElement: cloneElement,
+  createFactory: createFactory,
+  createMixin: function(mixin) {
+    // Currently a noop. Will be used to validate and trace mixins.
+    return mixin;
+  },
+  constructAndRenderComponent: ReactMount.constructAndRenderComponent,
+  constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
+  findDOMNode: findDOMNode,
+  render: render,
+  renderToString: ReactServerRendering.renderToString,
+  renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
+  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
+  isValidElement: ReactElement.isValidElement,
+  withContext: ReactContext.withContext,
+
+  // Hook for JSX spread, don't use this for anything else.
+  __spread: assign
+};
+
+// Inject the runtime into a devtools global hook regardless of browser.
+// Allows for debugging when the hook is injected on the page.
+if (
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
+  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
+    CurrentOwner: ReactCurrentOwner,
+    InstanceHandles: ReactInstanceHandles,
+    Mount: ReactMount,
+    Reconciler: ReactReconciler,
+    TextComponent: ReactDOMTextComponent
+  });
+}
+
+if ("production" !== "development") {
+  var ExecutionEnvironment = _dereq_(21);
+  if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
+
+    // If we're in Chrome, look for the devtools marker and provide a download
+    // link if not installed.
+    if (navigator.userAgent.indexOf('Chrome') > -1) {
+      if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
+        console.debug(
+          'Download the React DevTools for a better development experience: ' +
+          'http://fb.me/react-devtools'
+        );
+      }
+    }
+
+    var expectedFeatures = [
+      // shims
+      Array.isArray,
+      Array.prototype.every,
+      Array.prototype.forEach,
+      Array.prototype.indexOf,
+      Array.prototype.map,
+      Date.now,
+      Function.prototype.bind,
+      Object.keys,
+      String.prototype.split,
+      String.prototype.trim,
+
+      // shams
+      Object.create,
+      Object.freeze
+    ];
+
+    for (var i = 0; i < expectedFeatures.length; i++) {
+      if (!expectedFeatures[i]) {
+        console.error(
+          'One or more ES5 shim/shams expected by React are not available: ' +
+          'http://fb.me/react-warning-polyfills'
+        );
+        break;
+      }
+    }
+  }
+}
+
+React.version = '0.13.0';
+
+module.exports = React;
+
+},{"117":117,"144":144,"19":19,"21":21,"27":27,"32":32,"33":33,"34":34,"38":38,"39":39,"40":40,"51":51,"54":54,"57":57,"58":58,"66":66,"70":70,"75":75,"78":78,"81":81,"84":84}],2:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule AutoFocusMixin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var focusNode = _dereq_(119);
+
+var AutoFocusMixin = {
+  componentDidMount: function() {
+    if (this.props.autoFocus) {
+      focusNode(this.getDOMNode());
+    }
+  }
+};
+
+module.exports = AutoFocusMixin;
+
+},{"119":119}],3:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015 Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule BeforeInputEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPropagators = _dereq_(20);
+var ExecutionEnvironment = _dereq_(21);
+var FallbackCompositionState = _dereq_(22);
+var SyntheticCompositionEvent = _dereq_(93);
+var SyntheticInputEvent = _dereq_(97);
+
+var keyOf = _dereq_(141);
+
+var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
+var START_KEYCODE = 229;
+
+var canUseCompositionEvent = (
+  ExecutionEnvironment.canUseDOM &&
+  'CompositionEvent' in window
+);
+
+var documentMode = null;
+if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
+  documentMode = document.documentMode;
+}
+
+// Webkit offers a very useful `textInput` event that can be used to
+// directly represent `beforeInput`. The IE `textinput` event is not as
+// useful, so we don't use it.
+var canUseTextInputEvent = (
+  ExecutionEnvironment.canUseDOM &&
+  'TextEvent' in window &&
+  !documentMode &&
+  !isPresto()
+);
+
+// In IE9+, we have access to composition events, but the data supplied
+// by the native compositionend event may be incorrect. Japanese ideographic
+// spaces, for instance (\u3000) are not recorded correctly.
+var useFallbackCompositionData = (
+  ExecutionEnvironment.canUseDOM &&
+  (
+    (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11)
+  )
+);
+
+/**
+ * Opera <= 12 includes TextEvent in window, but does not fire
+ * text input events. Rely on keypress instead.
+ */
+function isPresto() {
+  var opera = window.opera;
+  return (
+    typeof opera === 'object' &&
+    typeof opera.version === 'function' &&
+    parseInt(opera.version(), 10) <= 12
+  );
+}
+
+var SPACEBAR_CODE = 32;
+var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+// Events and their corresponding property names.
+var eventTypes = {
+  beforeInput: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onBeforeInput: null}),
+      captured: keyOf({onBeforeInputCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topCompositionEnd,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topTextInput,
+      topLevelTypes.topPaste
+    ]
+  },
+  compositionEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionEnd: null}),
+      captured: keyOf({onCompositionEndCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionEnd,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  },
+  compositionStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionStart: null}),
+      captured: keyOf({onCompositionStartCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionStart,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  },
+  compositionUpdate: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionUpdate: null}),
+      captured: keyOf({onCompositionUpdateCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionUpdate,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  }
+};
+
+// Track whether we've ever handled a keypress on the space key.
+var hasSpaceKeypress = false;
+
+/**
+ * Return whether a native keypress event is assumed to be a command.
+ * This is required because Firefox fires `keypress` events for key commands
+ * (cut, copy, select-all, etc.) even though no character is inserted.
+ */
+function isKeypressCommand(nativeEvent) {
+  return (
+    (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
+    // ctrlKey && altKey is equivalent to AltGr, and is not a command.
+    !(nativeEvent.ctrlKey && nativeEvent.altKey)
+  );
+}
+
+
+/**
+ * Translate native top level events into event types.
+ *
+ * @param {string} topLevelType
+ * @return {object}
+ */
+function getCompositionEventType(topLevelType) {
+  switch (topLevelType) {
+    case topLevelTypes.topCompositionStart:
+      return eventTypes.compositionStart;
+    case topLevelTypes.topCompositionEnd:
+      return eventTypes.compositionEnd;
+    case topLevelTypes.topCompositionUpdate:
+      return eventTypes.compositionUpdate;
+  }
+}
+
+/**
+ * Does our fallback best-guess model think this event signifies that
+ * composition has begun?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackCompositionStart(topLevelType, nativeEvent) {
+  return (
+    topLevelType === topLevelTypes.topKeyDown &&
+    nativeEvent.keyCode === START_KEYCODE
+  );
+}
+
+/**
+ * Does our fallback mode think that this event is the end of composition?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackCompositionEnd(topLevelType, nativeEvent) {
+  switch (topLevelType) {
+    case topLevelTypes.topKeyUp:
+      // Command keys insert or clear IME input.
+      return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
+    case topLevelTypes.topKeyDown:
+      // Expect IME keyCode on each keydown. If we get any other
+      // code we must have exited earlier.
+      return (nativeEvent.keyCode !== START_KEYCODE);
+    case topLevelTypes.topKeyPress:
+    case topLevelTypes.topMouseDown:
+    case topLevelTypes.topBlur:
+      // Events are not possible without cancelling IME.
+      return true;
+    default:
+      return false;
+  }
+}
+
+/**
+ * Google Input Tools provides composition data via a CustomEvent,
+ * with the `data` property populated in the `detail` object. If this
+ * is available on the event object, use it. If not, this is a plain
+ * composition event and we have nothing special to extract.
+ *
+ * @param {object} nativeEvent
+ * @return {?string}
+ */
+function getDataFromCustomEvent(nativeEvent) {
+  var detail = nativeEvent.detail;
+  if (typeof detail === 'object' && 'data' in detail) {
+    return detail.data;
+  }
+  return null;
+}
+
+// Track the current IME composition fallback object, if any.
+var currentComposition = null;
+
+/**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?object} A SyntheticCompositionEvent.
+ */
+function extractCompositionEvent(
+  topLevelType,
+  topLevelTarget,
+  topLevelTargetID,
+  nativeEvent
+) {
+  var eventType;
+  var fallbackData;
+
+  if (canUseCompositionEvent) {
+    eventType = getCompositionEventType(topLevelType);
+  } else if (!currentComposition) {
+    if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
+      eventType = eventTypes.compositionStart;
+    }
+  } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
+    eventType = eventTypes.compositionEnd;
+  }
+
+  if (!eventType) {
+    return null;
+  }
+
+  if (useFallbackCompositionData) {
+    // The current composition is stored statically and must not be
+    // overwritten while composition continues.
+    if (!currentComposition && eventType === eventTypes.compositionStart) {
+      currentComposition = FallbackCompositionState.getPooled(topLevelTarget);
+    } else if (eventType === eventTypes.compositionEnd) {
+      if (currentComposition) {
+        fallbackData = currentComposition.getData();
+      }
+    }
+  }
+
+  var event = SyntheticCompositionEvent.getPooled(
+    eventType,
+    topLevelTargetID,
+    nativeEvent
+  );
+
+  if (fallbackData) {
+    // Inject data generated from fallback path into the synthetic event.
+    // This matches the property of native CompositionEventInterface.
+    event.data = fallbackData;
+  } else {
+    var customData = getDataFromCustomEvent(nativeEvent);
+    if (customData !== null) {
+      event.data = customData;
+    }
+  }
+
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+  return event;
+}
+
+/**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?string} The string corresponding to this `beforeInput` event.
+ */
+function getNativeBeforeInputChars(topLevelType, nativeEvent) {
+  switch (topLevelType) {
+    case topLevelTypes.topCompositionEnd:
+      return getDataFromCustomEvent(nativeEvent);
+    case topLevelTypes.topKeyPress:
+      /**
+       * If native `textInput` events are available, our goal is to make
+       * use of them. However, there is a special case: the spacebar key.
+       * In Webkit, preventing default on a spacebar `textInput` event
+       * cancels character insertion, but it *also* causes the browser
+       * to fall back to its default spacebar behavior of scrolling the
+       * page.
+       *
+       * Tracking at:
+       * https://code.google.com/p/chromium/issues/detail?id=355103
+       *
+       * To avoid this issue, use the keypress event as if no `textInput`
+       * event is available.
+       */
+      var which = nativeEvent.which;
+      if (which !== SPACEBAR_CODE) {
+        return null;
+      }
+
+      hasSpaceKeypress = true;
+      return SPACEBAR_CHAR;
+
+    case topLevelTypes.topTextInput:
+      // Record the characters to be added to the DOM.
+      var chars = nativeEvent.data;
+
+      // If it's a spacebar character, assume that we have already handled
+      // it at the keypress level and bail immediately. Android Chrome
+      // doesn't give us keycodes, so we need to blacklist it.
+      if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
+        return null;
+      }
+
+      return chars;
+
+    default:
+      // For other native event types, do nothing.
+      return null;
+  }
+}
+
+/**
+ * For browsers that do not provide the `textInput` event, extract the
+ * appropriate string to use for SyntheticInputEvent.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?string} The fallback string for this `beforeInput` event.
+ */
+function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
+  // If we are currently composing (IME) and using a fallback to do so,
+  // try to extract the composed characters from the fallback object.
+  if (currentComposition) {
+    if (
+      topLevelType === topLevelTypes.topCompositionEnd ||
+      isFallbackCompositionEnd(topLevelType, nativeEvent)
+    ) {
+      var chars = currentComposition.getData();
+      FallbackCompositionState.release(currentComposition);
+      currentComposition = null;
+      return chars;
+    }
+    return null;
+  }
+
+  switch (topLevelType) {
+    case topLevelTypes.topPaste:
+      // If a paste event occurs after a keypress, throw out the input
+      // chars. Paste events should not lead to BeforeInput events.
+      return null;
+    case topLevelTypes.topKeyPress:
+      /**
+       * As of v27, Firefox may fire keypress events even when no character
+       * will be inserted. A few possibilities:
+       *
+       * - `which` is `0`. Arrow keys, Esc key, etc.
+       *
+       * - `which` is the pressed key code, but no char is available.
+       *   Ex: 'AltGr + d` in Polish. There is no modified character for
+       *   this key combination and no character is inserted into the
+       *   document, but FF fires the keypress for char code `100` anyway.
+       *   No `input` event will occur.
+       *
+       * - `which` is the pressed key code, but a command combination is
+       *   being used. Ex: `Cmd+C`. No character is inserted, and no
+       *   `input` event will occur.
+       */
+      if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
+        return String.fromCharCode(nativeEvent.which);
+      }
+      return null;
+    case topLevelTypes.topCompositionEnd:
+      return useFallbackCompositionData ? null : nativeEvent.data;
+    default:
+      return null;
+  }
+}
+
+/**
+ * Extract a SyntheticInputEvent for `beforeInput`, based on either native
+ * `textInput` or fallback behavior.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?object} A SyntheticInputEvent.
+ */
+function extractBeforeInputEvent(
+  topLevelType,
+  topLevelTarget,
+  topLevelTargetID,
+  nativeEvent
+) {
+  var chars;
+
+  if (canUseTextInputEvent) {
+    chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
+  } else {
+    chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
+  }
+
+  // If no characters are being inserted, no BeforeInput event should
+  // be fired.
+  if (!chars) {
+    return null;
+  }
+
+  var event = SyntheticInputEvent.getPooled(
+    eventTypes.beforeInput,
+    topLevelTargetID,
+    nativeEvent
+  );
+
+  event.data = chars;
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+  return event;
+}
+
+/**
+ * Create an `onBeforeInput` event to match
+ * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
+ *
+ * This event plugin is based on the native `textInput` event
+ * available in Chrome, Safari, Opera, and IE. This event fires after
+ * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
+ *
+ * `beforeInput` is spec'd but not implemented in any browsers, and
+ * the `input` event does not provide any useful information about what has
+ * actually been added, contrary to the spec. Thus, `textInput` is the best
+ * available event to identify the characters that have actually been inserted
+ * into the target node.
+ *
+ * This plugin is also responsible for emitting `composition` events, thus
+ * allowing us to share composition fallback code for both `beforeInput` and
+ * `composition` event types.
+ */
+var BeforeInputEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID,
+    nativeEvent
+  ) {
+    return [
+      extractCompositionEvent(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent
+      ),
+      extractBeforeInputEvent(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent
+      )
+    ];
+  }
+};
+
+module.exports = BeforeInputEventPlugin;
+
+},{"141":141,"15":15,"20":20,"21":21,"22":22,"93":93,"97":97}],4:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSProperty
+ */
+
+'use strict';
+
+/**
+ * CSS properties which accept numbers but are not in units of "px".
+ */
+var isUnitlessNumber = {
+  boxFlex: true,
+  boxFlexGroup: true,
+  columnCount: true,
+  flex: true,
+  flexGrow: true,
+  flexShrink: true,
+  fontWeight: true,
+  lineClamp: true,
+  lineHeight: true,
+  opacity: true,
+  order: true,
+  orphans: true,
+  widows: true,
+  zIndex: true,
+  zoom: true,
+
+  // SVG-related properties
+  fillOpacity: true,
+  strokeOpacity: true
+};
+
+/**
+ * @param {string} prefix vendor-specific prefix, eg: Webkit
+ * @param {string} key style name, eg: transitionDuration
+ * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
+ * WebkitTransitionDuration
+ */
+function prefixKey(prefix, key) {
+  return prefix + key.charAt(0).toUpperCase() + key.substring(1);
+}
+
+/**
+ * Support style names that may come passed in prefixed by adding permutations
+ * of vendor prefixes.
+ */
+var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
+
+// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
+// infinite loop, because it iterates over the newly added props too.
+Object.keys(isUnitlessNumber).forEach(function(prop) {
+  prefixes.forEach(function(prefix) {
+    isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
+  });
+});
+
+/**
+ * Most style properties can be unset by doing .style[prop] = '' but IE8
+ * doesn't like doing that with shorthand properties so for the properties that
+ * IE8 breaks on, which are listed here, we instead unset each of the
+ * individual properties. See http://bugs.jquery.com/ticket/12385.
+ * The 4-value 'clock' properties like margin, padding, border-width seem to
+ * behave without any problems. Curiously, list-style works too without any
+ * special prodding.
+ */
+var shorthandPropertyExpansions = {
+  background: {
+    backgroundImage: true,
+    backgroundPosition: true,
+    backgroundRepeat: true,
+    backgroundColor: true
+  },
+  border: {
+    borderWidth: true,
+    borderStyle: true,
+    borderColor: true
+  },
+  borderBottom: {
+    borderBottomWidth: true,
+    borderBottomStyle: true,
+    borderBottomColor: true
+  },
+  borderLeft: {
+    borderLeftWidth: true,
+    borderLeftStyle: true,
+    borderLeftColor: true
+  },
+  borderRight: {
+    borderRightWidth: true,
+    borderRightStyle: true,
+    borderRightColor: true
+  },
+  borderTop: {
+    borderTopWidth: true,
+    borderTopStyle: true,
+    borderTopColor: true
+  },
+  font: {
+    fontStyle: true,
+    fontVariant: true,
+    fontWeight: true,
+    fontSize: true,
+    lineHeight: true,
+    fontFamily: true
+  }
+};
+
+var CSSProperty = {
+  isUnitlessNumber: isUnitlessNumber,
+  shorthandPropertyExpansions: shorthandPropertyExpansions
+};
+
+module.exports = CSSProperty;
+
+},{}],5:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSPropertyOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CSSProperty = _dereq_(4);
+var ExecutionEnvironment = _dereq_(21);
+
+var camelizeStyleName = _dereq_(108);
+var dangerousStyleValue = _dereq_(113);
+var hyphenateStyleName = _dereq_(133);
+var memoizeStringOnly = _dereq_(143);
+var warning = _dereq_(154);
+
+var processStyleName = memoizeStringOnly(function(styleName) {
+  return hyphenateStyleName(styleName);
+});
+
+var styleFloatAccessor = 'cssFloat';
+if (ExecutionEnvironment.canUseDOM) {
+  // IE8 only supports accessing cssFloat (standard) as styleFloat
+  if (document.documentElement.style.cssFloat === undefined) {
+    styleFloatAccessor = 'styleFloat';
+  }
+}
+
+if ("production" !== "development") {
+  // 'msTransform' is correct, but the other prefixes should be capitalized
+  var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;
+
+  // style values shouldn't contain a semicolon
+  var badStyleValueWithSemicolonPattern = /;\s*$/;
+
+  var warnedStyleNames = {};
+  var warnedStyleValues = {};
+
+  var warnHyphenatedStyleName = function(name) {
+    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
+      return;
+    }
+
+    warnedStyleNames[name] = true;
+    ("production" !== "development" ? warning(
+      false,
+      'Unsupported style property %s. Did you mean %s?',
+      name,
+      camelizeStyleName(name)
+    ) : null);
+  };
+
+  var warnBadVendoredStyleName = function(name) {
+    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
+      return;
+    }
+
+    warnedStyleNames[name] = true;
+    ("production" !== "development" ? warning(
+      false,
+      'Unsupported vendor-prefixed style property %s. Did you mean %s?',
+      name,
+      name.charAt(0).toUpperCase() + name.slice(1)
+    ) : null);
+  };
+
+  var warnStyleValueWithSemicolon = function(name, value) {
+    if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
+      return;
+    }
+
+    warnedStyleValues[value] = true;
+    ("production" !== "development" ? warning(
+      false,
+      'Style property values shouldn\'t contain a semicolon. ' +
+      'Try "%s: %s" instead.',
+      name,
+      value.replace(badStyleValueWithSemicolonPattern, '')
+    ) : null);
+  };
+
+  /**
+   * @param {string} name
+   * @param {*} value
+   */
+  var warnValidStyle = function(name, value) {
+    if (name.indexOf('-') > -1) {
+      warnHyphenatedStyleName(name);
+    } else if (badVendoredStyleNamePattern.test(name)) {
+      warnBadVendoredStyleName(name);
+    } else if (badStyleValueWithSemicolonPattern.test(value)) {
+      warnStyleValueWithSemicolon(name, value);
+    }
+  };
+}
+
+/**
+ * Operations for dealing with CSS properties.
+ */
+var CSSPropertyOperations = {
+
+  /**
+   * Serializes a mapping of style properties for use as inline styles:
+   *
+   *   > createMarkupForStyles({width: '200px', height: 0})
+   *   "width:200px;height:0;"
+   *
+   * Undefined values are ignored so that declarative programming is easier.
+   * The result should be HTML-escaped before insertion into the DOM.
+   *
+   * @param {object} styles
+   * @return {?string}
+   */
+  createMarkupForStyles: function(styles) {
+    var serialized = '';
+    for (var styleName in styles) {
+      if (!styles.hasOwnProperty(styleName)) {
+        continue;
+      }
+      var styleValue = styles[styleName];
+      if ("production" !== "development") {
+        warnValidStyle(styleName, styleValue);
+      }
+      if (styleValue != null) {
+        serialized += processStyleName(styleName) + ':';
+        serialized += dangerousStyleValue(styleName, styleValue) + ';';
+      }
+    }
+    return serialized || null;
+  },
+
+  /**
+   * Sets the value for multiple styles on a node.  If a value is specified as
+   * '' (empty string), the corresponding style property will be unset.
+   *
+   * @param {DOMElement} node
+   * @param {object} styles
+   */
+  setValueForStyles: function(node, styles) {
+    var style = node.style;
+    for (var styleName in styles) {
+      if (!styles.hasOwnProperty(styleName)) {
+        continue;
+      }
+      if ("production" !== "development") {
+        warnValidStyle(styleName, styles[styleName]);
+      }
+      var styleValue = dangerousStyleValue(styleName, styles[styleName]);
+      if (styleName === 'float') {
+        styleName = styleFloatAccessor;
+      }
+      if (styleValue) {
+        style[styleName] = styleValue;
+      } else {
+        var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+        if (expansion) {
+          // Shorthand property that IE8 won't like unsetting, so unset each
+          // component to placate it
+          for (var individualStyleName in expansion) {
+            style[individualStyleName] = '';
+          }
+        } else {
+          style[styleName] = '';
+        }
+      }
+    }
+  }
+
+};
+
+module.exports = CSSPropertyOperations;
+
+},{"108":108,"113":113,"133":133,"143":143,"154":154,"21":21,"4":4}],6:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CallbackQueue
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+
+/**
+ * A specialized pseudo-event module to help keep track of components waiting to
+ * be notified when their DOM representations are available for use.
+ *
+ * This implements `PooledClass`, so you should never need to instantiate this.
+ * Instead, use `CallbackQueue.getPooled()`.
+ *
+ * @class ReactMountReady
+ * @implements PooledClass
+ * @internal
+ */
+function CallbackQueue() {
+  this._callbacks = null;
+  this._contexts = null;
+}
+
+assign(CallbackQueue.prototype, {
+
+  /**
+   * Enqueues a callback to be invoked when `notifyAll` is invoked.
+   *
+   * @param {function} callback Invoked when `notifyAll` is invoked.
+   * @param {?object} context Context to call `callback` with.
+   * @internal
+   */
+  enqueue: function(callback, context) {
+    this._callbacks = this._callbacks || [];
+    this._contexts = this._contexts || [];
+    this._callbacks.push(callback);
+    this._contexts.push(context);
+  },
+
+  /**
+   * Invokes all enqueued callbacks and clears the queue. This is invoked after
+   * the DOM representation of a component has been created or updated.
+   *
+   * @internal
+   */
+  notifyAll: function() {
+    var callbacks = this._callbacks;
+    var contexts = this._contexts;
+    if (callbacks) {
+      ("production" !== "development" ? invariant(
+        callbacks.length === contexts.length,
+        'Mismatched list of contexts in callback queue'
+      ) : invariant(callbacks.length === contexts.length));
+      this._callbacks = null;
+      this._contexts = null;
+      for (var i = 0, l = callbacks.length; i < l; i++) {
+        callbacks[i].call(contexts[i]);
+      }
+      callbacks.length = 0;
+      contexts.length = 0;
+    }
+  },
+
+  /**
+   * Resets the internal queue.
+   *
+   * @internal
+   */
+  reset: function() {
+    this._callbacks = null;
+    this._contexts = null;
+  },
+
+  /**
+   * `PooledClass` looks for this.
+   */
+  destructor: function() {
+    this.reset();
+  }
+
+});
+
+PooledClass.addPoolingTo(CallbackQueue);
+
+module.exports = CallbackQueue;
+
+},{"135":135,"27":27,"28":28}],7:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ChangeEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPluginHub = _dereq_(17);
+var EventPropagators = _dereq_(20);
+var ExecutionEnvironment = _dereq_(21);
+var ReactUpdates = _dereq_(87);
+var SyntheticEvent = _dereq_(95);
+
+var isEventSupported = _dereq_(136);
+var isTextInputElement = _dereq_(138);
+var keyOf = _dereq_(141);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  change: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onChange: null}),
+      captured: keyOf({onChangeCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topChange,
+      topLevelTypes.topClick,
+      topLevelTypes.topFocus,
+      topLevelTypes.topInput,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topSelectionChange
+    ]
+  }
+};
+
+/**
+ * For IE shims
+ */
+var activeElement = null;
+var activeElementID = null;
+var activeElementValue = null;
+var activeElementValueProp = null;
+
+/**
+ * SECTION: handle `change` event
+ */
+function shouldUseChangeEvent(elem) {
+  return (
+    elem.nodeName === 'SELECT' ||
+    (elem.nodeName === 'INPUT' && elem.type === 'file')
+  );
+}
+
+var doesChangeEventBubble = false;
+if (ExecutionEnvironment.canUseDOM) {
+  // See `handleChange` comment below
+  doesChangeEventBubble = isEventSupported('change') && (
+    (!('documentMode' in document) || document.documentMode > 8)
+  );
+}
+
+function manualDispatchChangeEvent(nativeEvent) {
+  var event = SyntheticEvent.getPooled(
+    eventTypes.change,
+    activeElementID,
+    nativeEvent
+  );
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+
+  // If change and propertychange bubbled, we'd just bind to it like all the
+  // other events and have it go through ReactBrowserEventEmitter. Since it
+  // doesn't, we manually listen for the events and so we have to enqueue and
+  // process the abstract event manually.
+  //
+  // Batching is necessary here in order to ensure that all event handlers run
+  // before the next rerender (including event handlers attached to ancestor
+  // elements instead of directly on the input). Without this, controlled
+  // components don't work properly in conjunction with event bubbling because
+  // the component is rerendered and the value reverted before all the event
+  // handlers can run. See https://github.com/facebook/react/issues/708.
+  ReactUpdates.batchedUpdates(runEventInBatch, event);
+}
+
+function runEventInBatch(event) {
+  EventPluginHub.enqueueEvents(event);
+  EventPluginHub.processEventQueue();
+}
+
+function startWatchingForChangeEventIE8(target, targetID) {
+  activeElement = target;
+  activeElementID = targetID;
+  activeElement.attachEvent('onchange', manualDispatchChangeEvent);
+}
+
+function stopWatchingForChangeEventIE8() {
+  if (!activeElement) {
+    return;
+  }
+  activeElement.detachEvent('onchange', manualDispatchChangeEvent);
+  activeElement = null;
+  activeElementID = null;
+}
+
+function getTargetIDForChangeEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topChange) {
+    return topLevelTargetID;
+  }
+}
+function handleEventsForChangeEventIE8(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topFocus) {
+    // stopWatching() should be a noop here but we call it just in case we
+    // missed a blur event somehow.
+    stopWatchingForChangeEventIE8();
+    startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
+  } else if (topLevelType === topLevelTypes.topBlur) {
+    stopWatchingForChangeEventIE8();
+  }
+}
+
+
+/**
+ * SECTION: handle `input` event
+ */
+var isInputEventSupported = false;
+if (ExecutionEnvironment.canUseDOM) {
+  // IE9 claims to support the input event but fails to trigger it when
+  // deleting text, so we ignore its input events
+  isInputEventSupported = isEventSupported('input') && (
+    (!('documentMode' in document) || document.documentMode > 9)
+  );
+}
+
+/**
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
+ * set on the active element.
+ */
+var newValueProp =  {
+  get: function() {
+    return activeElementValueProp.get.call(this);
+  },
+  set: function(val) {
+    // Cast to a string so we can do equality checks.
+    activeElementValue = '' + val;
+    activeElementValueProp.set.call(this, val);
+  }
+};
+
+/**
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
+ * and override the value property so that we can distinguish user events from
+ * value changes in JS.
+ */
+function startWatchingForValueChange(target, targetID) {
+  activeElement = target;
+  activeElementID = targetID;
+  activeElementValue = target.value;
+  activeElementValueProp = Object.getOwnPropertyDescriptor(
+    target.constructor.prototype,
+    'value'
+  );
+
+  Object.defineProperty(activeElement, 'value', newValueProp);
+  activeElement.attachEvent('onpropertychange', handlePropertyChange);
+}
+
+/**
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
+ * if any exists.
+ */
+function stopWatchingForValueChange() {
+  if (!activeElement) {
+    return;
+  }
+
+  // delete restores the original property definition
+  delete activeElement.value;
+  activeElement.detachEvent('onpropertychange', handlePropertyChange);
+
+  activeElement = null;
+  activeElementID = null;
+  activeElementValue = null;
+  activeElementValueProp = null;
+}
+
+/**
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
+ * the value of the active element has changed.
+ */
+function handlePropertyChange(nativeEvent) {
+  if (nativeEvent.propertyName !== 'value') {
+    return;
+  }
+  var value = nativeEvent.srcElement.value;
+  if (value === activeElementValue) {
+    return;
+  }
+  activeElementValue = value;
+
+  manualDispatchChangeEvent(nativeEvent);
+}
+
+/**
+ * If a `change` event should be fired, returns the target's ID.
+ */
+function getTargetIDForInputEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topInput) {
+    // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
+    // what we want so fall through here and trigger an abstract event
+    return topLevelTargetID;
+  }
+}
+
+// For IE8 and IE9.
+function handleEventsForInputEventIE(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topFocus) {
+    // In IE8, we can capture almost all .value changes by adding a
+    // propertychange handler and looking for events with propertyName
+    // equal to 'value'
+    // In IE9, propertychange fires for most input events but is buggy and
+    // doesn't fire when text is deleted, but conveniently, selectionchange
+    // appears to fire in all of the remaining cases so we catch those and
+    // forward the event if the value has changed
+    // In either case, we don't want to call the event handler if the value
+    // is changed from JS so we redefine a setter for `.value` that updates
+    // our activeElementValue variable, allowing us to ignore those changes
+    //
+    // stopWatching() should be a noop here but we call it just in case we
+    // missed a blur event somehow.
+    stopWatchingForValueChange();
+    startWatchingForValueChange(topLevelTarget, topLevelTargetID);
+  } else if (topLevelType === topLevelTypes.topBlur) {
+    stopWatchingForValueChange();
+  }
+}
+
+// For IE8 and IE9.
+function getTargetIDForInputEventIE(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topSelectionChange ||
+      topLevelType === topLevelTypes.topKeyUp ||
+      topLevelType === topLevelTypes.topKeyDown) {
+    // On the selectionchange event, the target is just document which isn't
+    // helpful for us so just check activeElement instead.
+    //
+    // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
+    // propertychange on the first input event after setting `value` from a
+    // script and fires only keydown, keypress, keyup. Catching keyup usually
+    // gets it and catching keydown lets us fire an event for the first
+    // keystroke if user does a key repeat (it'll be a little delayed: right
+    // before the second keystroke). Other input methods (e.g., paste) seem to
+    // fire selectionchange normally.
+    if (activeElement && activeElement.value !== activeElementValue) {
+      activeElementValue = activeElement.value;
+      return activeElementID;
+    }
+  }
+}
+
+
+/**
+ * SECTION: handle `click` event
+ */
+function shouldUseClickEvent(elem) {
+  // Use the `click` event to detect changes to checkbox and radio inputs.
+  // This approach works across all browsers, whereas `change` does not fire
+  // until `blur` in IE8.
+  return (
+    elem.nodeName === 'INPUT' &&
+    (elem.type === 'checkbox' || elem.type === 'radio')
+  );
+}
+
+function getTargetIDForClickEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topClick) {
+    return topLevelTargetID;
+  }
+}
+
+/**
+ * This plugin creates an `onChange` event that normalizes change events
+ * across form elements. This event fires at a time when it's possible to
+ * change the element's value without seeing a flicker.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - select
+ */
+var ChangeEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+
+    var getTargetIDFunc, handleEventFunc;
+    if (shouldUseChangeEvent(topLevelTarget)) {
+      if (doesChangeEventBubble) {
+        getTargetIDFunc = getTargetIDForChangeEvent;
+      } else {
+        handleEventFunc = handleEventsForChangeEventIE8;
+      }
+    } else if (isTextInputElement(topLevelTarget)) {
+      if (isInputEventSupported) {
+        getTargetIDFunc = getTargetIDForInputEvent;
+      } else {
+        getTargetIDFunc = getTargetIDForInputEventIE;
+        handleEventFunc = handleEventsForInputEventIE;
+      }
+    } else if (shouldUseClickEvent(topLevelTarget)) {
+      getTargetIDFunc = getTargetIDForClickEvent;
+    }
+
+    if (getTargetIDFunc) {
+      var targetID = getTargetIDFunc(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID
+      );
+      if (targetID) {
+        var event = SyntheticEvent.getPooled(
+          eventTypes.change,
+          targetID,
+          nativeEvent
+        );
+        EventPropagators.accumulateTwoPhaseDispatches(event);
+        return event;
+      }
+    }
+
+    if (handleEventFunc) {
+      handleEventFunc(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID
+      );
+    }
+  }
+
+};
+
+module.exports = ChangeEventPlugin;
+
+},{"136":136,"138":138,"141":141,"15":15,"17":17,"20":20,"21":21,"87":87,"95":95}],8:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ClientReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+var nextReactRootIndex = 0;
+
+var ClientReactRootIndex = {
+  createReactRootIndex: function() {
+    return nextReactRootIndex++;
+  }
+};
+
+module.exports = ClientReactRootIndex;
+
+},{}],9:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMChildrenOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var Danger = _dereq_(12);
+var ReactMultiChildUpdateTypes = _dereq_(72);
+
+var setTextContent = _dereq_(149);
+var invariant = _dereq_(135);
+
+/**
+ * Inserts `childNode` as a child of `parentNode` at the `index`.
+ *
+ * @param {DOMElement} parentNode Parent node in which to insert.
+ * @param {DOMElement} childNode Child node to insert.
+ * @param {number} index Index at which to insert the child.
+ * @internal
+ */
+function insertChildAt(parentNode, childNode, index) {
+  // By exploiting arrays returning `undefined` for an undefined index, we can
+  // rely exclusively on `insertBefore(node, null)` instead of also using
+  // `appendChild(node)`. However, using `undefined` is not allowed by all
+  // browsers so we must replace it with `null`.
+  parentNode.insertBefore(
+    childNode,
+    parentNode.childNodes[index] || null
+  );
+}
+
+/**
+ * Operations for updating with DOM children.
+ */
+var DOMChildrenOperations = {
+
+  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
+
+  updateTextContent: setTextContent,
+
+  /**
+   * Updates a component's children by processing a series of updates. The
+   * update configurations are each expected to have a `parentNode` property.
+   *
+   * @param {array<object>} updates List of update configurations.
+   * @param {array<string>} markupList List of markup strings.
+   * @internal
+   */
+  processUpdates: function(updates, markupList) {
+    var update;
+    // Mapping from parent IDs to initial child orderings.
+    var initialChildren = null;
+    // List of children that will be moved or removed.
+    var updatedChildren = null;
+
+    for (var i = 0; i < updates.length; i++) {
+      update = updates[i];
+      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
+          update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
+        var updatedIndex = update.fromIndex;
+        var updatedChild = update.parentNode.childNodes[updatedIndex];
+        var parentID = update.parentID;
+
+        ("production" !== "development" ? invariant(
+          updatedChild,
+          'processUpdates(): Unable to find child %s of element. This ' +
+          'probably means the DOM was unexpectedly mutated (e.g., by the ' +
+          'browser), usually due to forgetting a <tbody> when using tables, ' +
+          'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' +
+          'in an <svg> parent. Try inspecting the child nodes of the element ' +
+          'with React ID `%s`.',
+          updatedIndex,
+          parentID
+        ) : invariant(updatedChild));
+
+        initialChildren = initialChildren || {};
+        initialChildren[parentID] = initialChildren[parentID] || [];
+        initialChildren[parentID][updatedIndex] = updatedChild;
+
+        updatedChildren = updatedChildren || [];
+        updatedChildren.push(updatedChild);
+      }
+    }
+
+    var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
+
+    // Remove updated children first so that `toIndex` is consistent.
+    if (updatedChildren) {
+      for (var j = 0; j < updatedChildren.length; j++) {
+        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
+      }
+    }
+
+    for (var k = 0; k < updates.length; k++) {
+      update = updates[k];
+      switch (update.type) {
+        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
+          insertChildAt(
+            update.parentNode,
+            renderedMarkup[update.markupIndex],
+            update.toIndex
+          );
+          break;
+        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
+          insertChildAt(
+            update.parentNode,
+            initialChildren[update.parentID][update.fromIndex],
+            update.toIndex
+          );
+          break;
+        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
+          setTextContent(
+            update.parentNode,
+            update.textContent
+          );
+          break;
+        case ReactMultiChildUpdateTypes.REMOVE_NODE:
+          // Already removed by the for-loop above.
+          break;
+      }
+    }
+  }
+
+};
+
+module.exports = DOMChildrenOperations;
+
+},{"12":12,"135":135,"149":149,"72":72}],10:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMProperty
+ * @typechecks static-only
+ */
+
+/*jslint bitwise: true */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+function checkMask(value, bitmask) {
+  return (value & bitmask) === bitmask;
+}
+
+var DOMPropertyInjection = {
+  /**
+   * Mapping from normalized, camelcased property names to a configuration that
+   * specifies how the associated DOM property should be accessed or rendered.
+   */
+  MUST_USE_ATTRIBUTE: 0x1,
+  MUST_USE_PROPERTY: 0x2,
+  HAS_SIDE_EFFECTS: 0x4,
+  HAS_BOOLEAN_VALUE: 0x8,
+  HAS_NUMERIC_VALUE: 0x10,
+  HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
+  HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
+
+  /**
+   * Inject some specialized knowledge about the DOM. This takes a config object
+   * with the following properties:
+   *
+   * isCustomAttribute: function that given an attribute name will return true
+   * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
+   * attributes where it's impossible to enumerate all of the possible
+   * attribute names,
+   *
+   * Properties: object mapping DOM property name to one of the
+   * DOMPropertyInjection constants or null. If your attribute isn't in here,
+   * it won't get written to the DOM.
+   *
+   * DOMAttributeNames: object mapping React attribute name to the DOM
+   * attribute name. Attribute names not specified use the **lowercase**
+   * normalized name.
+   *
+   * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
+   * Property names not specified use the normalized name.
+   *
+   * DOMMutationMethods: Properties that require special mutation methods. If
+   * `value` is undefined, the mutation method should unset the property.
+   *
+   * @param {object} domPropertyConfig the config as described above.
+   */
+  injectDOMPropertyConfig: function(domPropertyConfig) {
+    var Properties = domPropertyConfig.Properties || {};
+    var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
+    var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
+    var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
+
+    if (domPropertyConfig.isCustomAttribute) {
+      DOMProperty._isCustomAttributeFunctions.push(
+        domPropertyConfig.isCustomAttribute
+      );
+    }
+
+    for (var propName in Properties) {
+      ("production" !== "development" ? invariant(
+        !DOMProperty.isStandardName.hasOwnProperty(propName),
+        'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
+        '\'%s\' which has already been injected. You may be accidentally ' +
+        'injecting the same DOM property config twice, or you may be ' +
+        'injecting two configs that have conflicting property names.',
+        propName
+      ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));
+
+      DOMProperty.isStandardName[propName] = true;
+
+      var lowerCased = propName.toLowerCase();
+      DOMProperty.getPossibleStandardName[lowerCased] = propName;
+
+      if (DOMAttributeNames.hasOwnProperty(propName)) {
+        var attributeName = DOMAttributeNames[propName];
+        DOMProperty.getPossibleStandardName[attributeName] = propName;
+        DOMProperty.getAttributeName[propName] = attributeName;
+      } else {
+        DOMProperty.getAttributeName[propName] = lowerCased;
+      }
+
+      DOMProperty.getPropertyName[propName] =
+        DOMPropertyNames.hasOwnProperty(propName) ?
+          DOMPropertyNames[propName] :
+          propName;
+
+      if (DOMMutationMethods.hasOwnProperty(propName)) {
+        DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
+      } else {
+        DOMProperty.getMutationMethod[propName] = null;
+      }
+
+      var propConfig = Properties[propName];
+      DOMProperty.mustUseAttribute[propName] =
+        checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
+      DOMProperty.mustUseProperty[propName] =
+        checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
+      DOMProperty.hasSideEffects[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
+      DOMProperty.hasBooleanValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
+      DOMProperty.hasNumericValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
+      DOMProperty.hasPositiveNumericValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
+      DOMProperty.hasOverloadedBooleanValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);
+
+      ("production" !== "development" ? invariant(
+        !DOMProperty.mustUseAttribute[propName] ||
+          !DOMProperty.mustUseProperty[propName],
+        'DOMProperty: Cannot require using both attribute and property: %s',
+        propName
+      ) : invariant(!DOMProperty.mustUseAttribute[propName] ||
+        !DOMProperty.mustUseProperty[propName]));
+      ("production" !== "development" ? invariant(
+        DOMProperty.mustUseProperty[propName] ||
+          !DOMProperty.hasSideEffects[propName],
+        'DOMProperty: Properties that have side effects must use property: %s',
+        propName
+      ) : invariant(DOMProperty.mustUseProperty[propName] ||
+        !DOMProperty.hasSideEffects[propName]));
+      ("production" !== "development" ? invariant(
+        !!DOMProperty.hasBooleanValue[propName] +
+          !!DOMProperty.hasNumericValue[propName] +
+          !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
+        'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
+        'numeric value, but not a combination: %s',
+        propName
+      ) : invariant(!!DOMProperty.hasBooleanValue[propName] +
+        !!DOMProperty.hasNumericValue[propName] +
+        !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
+    }
+  }
+};
+var defaultValueCache = {};
+
+/**
+ * DOMProperty exports lookup objects that can be used like functions:
+ *
+ *   > DOMProperty.isValid['id']
+ *   true
+ *   > DOMProperty.isValid['foobar']
+ *   undefined
+ *
+ * Although this may be confusing, it performs better in general.
+ *
+ * @see http://jsperf.com/key-exists
+ * @see http://jsperf.com/key-missing
+ */
+var DOMProperty = {
+
+  ID_ATTRIBUTE_NAME: 'data-reactid',
+
+  /**
+   * Checks whether a property name is a standard property.
+   * @type {Object}
+   */
+  isStandardName: {},
+
+  /**
+   * Mapping from lowercase property names to the properly cased version, used
+   * to warn in the case of missing properties.
+   * @type {Object}
+   */
+  getPossibleStandardName: {},
+
+  /**
+   * Mapping from normalized names to attribute names that differ. Attribute
+   * names are used when rendering markup or with `*Attribute()`.
+   * @type {Object}
+   */
+  getAttributeName: {},
+
+  /**
+   * Mapping from normalized names to properties on DOM node instances.
+   * (This includes properties that mutate due to external factors.)
+   * @type {Object}
+   */
+  getPropertyName: {},
+
+  /**
+   * Mapping from normalized names to mutation methods. This will only exist if
+   * mutation cannot be set simply by the property or `setAttribute()`.
+   * @type {Object}
+   */
+  getMutationMethod: {},
+
+  /**
+   * Whether the property must be accessed and mutated as an object property.
+   * @type {Object}
+   */
+  mustUseAttribute: {},
+
+  /**
+   * Whether the property must be accessed and mutated using `*Attribute()`.
+   * (This includes anything that fails `<propName> in <element>`.)
+   * @type {Object}
+   */
+  mustUseProperty: {},
+
+  /**
+   * Whether or not setting a value causes side effects such as triggering
+   * resources to be loaded or text selection changes. We must ensure that
+   * the value is only set if it has changed.
+   * @type {Object}
+   */
+  hasSideEffects: {},
+
+  /**
+   * Whether the property should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasBooleanValue: {},
+
+  /**
+   * Whether the property must be numeric or parse as a
+   * numeric and should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasNumericValue: {},
+
+  /**
+   * Whether the property must be positive numeric or parse as a positive
+   * numeric and should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasPositiveNumericValue: {},
+
+  /**
+   * Whether the property can be used as a flag as well as with a value. Removed
+   * when strictly equal to false; present without a value when strictly equal
+   * to true; present with a value otherwise.
+   * @type {Object}
+   */
+  hasOverloadedBooleanValue: {},
+
+  /**
+   * All of the isCustomAttribute() functions that have been injected.
+   */
+  _isCustomAttributeFunctions: [],
+
+  /**
+   * Checks whether a property name is a custom attribute.
+   * @method
+   */
+  isCustomAttribute: function(attributeName) {
+    for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
+      var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
+      if (isCustomAttributeFn(attributeName)) {
+        return true;
+      }
+    }
+    return false;
+  },
+
+  /**
+   * Returns the default property value for a DOM property (i.e., not an
+   * attribute). Most default values are '' or false, but not all. Worse yet,
+   * some (in particular, `type`) vary depending on the type of element.
+   *
+   * TODO: Is it better to grab all the possible properties when creating an
+   * element to avoid having to create the same element twice?
+   */
+  getDefaultValueForProperty: function(nodeName, prop) {
+    var nodeDefaults = defaultValueCache[nodeName];
+    var testElement;
+    if (!nodeDefaults) {
+      defaultValueCache[nodeName] = nodeDefaults = {};
+    }
+    if (!(prop in nodeDefaults)) {
+      testElement = document.createElement(nodeName);
+      nodeDefaults[prop] = testElement[prop];
+    }
+    return nodeDefaults[prop];
+  },
+
+  injection: DOMPropertyInjection
+};
+
+module.exports = DOMProperty;
+
+},{"135":135}],11:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMPropertyOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+
+var quoteAttributeValueForBrowser = _dereq_(147);
+var warning = _dereq_(154);
+
+function shouldIgnoreValue(name, value) {
+  return value == null ||
+    (DOMProperty.hasBooleanValue[name] && !value) ||
+    (DOMProperty.hasNumericValue[name] && isNaN(value)) ||
+    (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) ||
+    (DOMProperty.hasOverloadedBooleanValue[name] && value === false);
+}
+
+if ("production" !== "development") {
+  var reactProps = {
+    children: true,
+    dangerouslySetInnerHTML: true,
+    key: true,
+    ref: true
+  };
+  var warnedProperties = {};
+
+  var warnUnknownProperty = function(name) {
+    if (reactProps.hasOwnProperty(name) && reactProps[name] ||
+        warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
+      return;
+    }
+
+    warnedProperties[name] = true;
+    var lowerCasedName = name.toLowerCase();
+
+    // data-* attributes should be lowercase; suggest the lowercase version
+    var standardName = (
+      DOMProperty.isCustomAttribute(lowerCasedName) ?
+        lowerCasedName :
+      DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
+        DOMProperty.getPossibleStandardName[lowerCasedName] :
+        null
+    );
+
+    // For now, only warn when we have a suggested correction. This prevents
+    // logging too much when using transferPropsTo.
+    ("production" !== "development" ? warning(
+      standardName == null,
+      'Unknown DOM property %s. Did you mean %s?',
+      name,
+      standardName
+    ) : null);
+
+  };
+}
+
+/**
+ * Operations for dealing with DOM properties.
+ */
+var DOMPropertyOperations = {
+
+  /**
+   * Creates markup for the ID property.
+   *
+   * @param {string} id Unescaped ID.
+   * @return {string} Markup string.
+   */
+  createMarkupForID: function(id) {
+    return DOMProperty.ID_ATTRIBUTE_NAME + '=' +
+      quoteAttributeValueForBrowser(id);
+  },
+
+  /**
+   * Creates markup for a property.
+   *
+   * @param {string} name
+   * @param {*} value
+   * @return {?string} Markup string, or null if the property was invalid.
+   */
+  createMarkupForProperty: function(name, value) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      if (shouldIgnoreValue(name, value)) {
+        return '';
+      }
+      var attributeName = DOMProperty.getAttributeName[name];
+      if (DOMProperty.hasBooleanValue[name] ||
+          (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
+        return attributeName;
+      }
+      return attributeName + '=' + quoteAttributeValueForBrowser(value);
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      if (value == null) {
+        return '';
+      }
+      return name + '=' + quoteAttributeValueForBrowser(value);
+    } else if ("production" !== "development") {
+      warnUnknownProperty(name);
+    }
+    return null;
+  },
+
+  /**
+   * Sets the value for a property on a node.
+   *
+   * @param {DOMElement} node
+   * @param {string} name
+   * @param {*} value
+   */
+  setValueForProperty: function(node, name, value) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      var mutationMethod = DOMProperty.getMutationMethod[name];
+      if (mutationMethod) {
+        mutationMethod(node, value);
+      } else if (shouldIgnoreValue(name, value)) {
+        this.deleteValueForProperty(node, name);
+      } else if (DOMProperty.mustUseAttribute[name]) {
+        // `setAttribute` with objects becomes only `[object]` in IE8/9,
+        // ('' + value) makes it output the correct toString()-value.
+        node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
+      } else {
+        var propName = DOMProperty.getPropertyName[name];
+        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
+        // property type before comparing; only `value` does and is string.
+        if (!DOMProperty.hasSideEffects[name] ||
+            ('' + node[propName]) !== ('' + value)) {
+          // Contrary to `setAttribute`, object properties are properly
+          // `toString`ed by IE8/9.
+          node[propName] = value;
+        }
+      }
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      if (value == null) {
+        node.removeAttribute(name);
+      } else {
+        node.setAttribute(name, '' + value);
+      }
+    } else if ("production" !== "development") {
+      warnUnknownProperty(name);
+    }
+  },
+
+  /**
+   * Deletes the value for a property on a node.
+   *
+   * @param {DOMElement} node
+   * @param {string} name
+   */
+  deleteValueForProperty: function(node, name) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      var mutationMethod = DOMProperty.getMutationMethod[name];
+      if (mutationMethod) {
+        mutationMethod(node, undefined);
+      } else if (DOMProperty.mustUseAttribute[name]) {
+        node.removeAttribute(DOMProperty.getAttributeName[name]);
+      } else {
+        var propName = DOMProperty.getPropertyName[name];
+        var defaultValue = DOMProperty.getDefaultValueForProperty(
+          node.nodeName,
+          propName
+        );
+        if (!DOMProperty.hasSideEffects[name] ||
+            ('' + node[propName]) !== defaultValue) {
+          node[propName] = defaultValue;
+        }
+      }
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      node.removeAttribute(name);
+    } else if ("production" !== "development") {
+      warnUnknownProperty(name);
+    }
+  }
+
+};
+
+module.exports = DOMPropertyOperations;
+
+},{"10":10,"147":147,"154":154}],12:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Danger
+ * @typechecks static-only
+ */
+
+/*jslint evil: true, sub: true */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+
+var createNodesFromMarkup = _dereq_(112);
+var emptyFunction = _dereq_(114);
+var getMarkupWrap = _dereq_(127);
+var invariant = _dereq_(135);
+
+var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
+var RESULT_INDEX_ATTR = 'data-danger-index';
+
+/**
+ * Extracts the `nodeName` from a string of markup.
+ *
+ * NOTE: Extracting the `nodeName` does not require a regular expression match
+ * because we make assumptions about React-generated markup (i.e. there are no
+ * spaces surrounding the opening tag and there is at least one attribute).
+ *
+ * @param {string} markup String of markup.
+ * @return {string} Node name of the supplied markup.
+ * @see http://jsperf.com/extract-nodename
+ */
+function getNodeName(markup) {
+  return markup.substring(1, markup.indexOf(' '));
+}
+
+var Danger = {
+
+  /**
+   * Renders markup into an array of nodes. The markup is expected to render
+   * into a list of root nodes. Also, the length of `resultList` and
+   * `markupList` should be the same.
+   *
+   * @param {array<string>} markupList List of markup strings to render.
+   * @return {array<DOMElement>} List of rendered nodes.
+   * @internal
+   */
+  dangerouslyRenderMarkup: function(markupList) {
+    ("production" !== "development" ? invariant(
+      ExecutionEnvironment.canUseDOM,
+      'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +
+      'thread. Make sure `window` and `document` are available globally ' +
+      'before requiring React when unit testing or use ' +
+      'React.renderToString for server rendering.'
+    ) : invariant(ExecutionEnvironment.canUseDOM));
+    var nodeName;
+    var markupByNodeName = {};
+    // Group markup by `nodeName` if a wrap is necessary, else by '*'.
+    for (var i = 0; i < markupList.length; i++) {
+      ("production" !== "development" ? invariant(
+        markupList[i],
+        'dangerouslyRenderMarkup(...): Missing markup.'
+      ) : invariant(markupList[i]));
+      nodeName = getNodeName(markupList[i]);
+      nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
+      markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
+      markupByNodeName[nodeName][i] = markupList[i];
+    }
+    var resultList = [];
+    var resultListAssignmentCount = 0;
+    for (nodeName in markupByNodeName) {
+      if (!markupByNodeName.hasOwnProperty(nodeName)) {
+        continue;
+      }
+      var markupListByNodeName = markupByNodeName[nodeName];
+
+      // This for-in loop skips the holes of the sparse array. The order of
+      // iteration should follow the order of assignment, which happens to match
+      // numerical index order, but we don't rely on that.
+      var resultIndex;
+      for (resultIndex in markupListByNodeName) {
+        if (markupListByNodeName.hasOwnProperty(resultIndex)) {
+          var markup = markupListByNodeName[resultIndex];
+
+          // Push the requested markup with an additional RESULT_INDEX_ATTR
+          // attribute.  If the markup does not start with a < character, it
+          // will be discarded below (with an appropriate console.error).
+          markupListByNodeName[resultIndex] = markup.replace(
+            OPEN_TAG_NAME_EXP,
+            // This index will be parsed back out below.
+            '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
+          );
+        }
+      }
+
+      // Render each group of markup with similar wrapping `nodeName`.
+      var renderNodes = createNodesFromMarkup(
+        markupListByNodeName.join(''),
+        emptyFunction // Do nothing special with <script> tags.
+      );
+
+      for (var j = 0; j < renderNodes.length; ++j) {
+        var renderNode = renderNodes[j];
+        if (renderNode.hasAttribute &&
+            renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
+
+          resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
+          renderNode.removeAttribute(RESULT_INDEX_ATTR);
+
+          ("production" !== "development" ? invariant(
+            !resultList.hasOwnProperty(resultIndex),
+            'Danger: Assigning to an already-occupied result index.'
+          ) : invariant(!resultList.hasOwnProperty(resultIndex)));
+
+          resultList[resultIndex] = renderNode;
+
+          // This should match resultList.length and markupList.length when
+          // we're done.
+          resultListAssignmentCount += 1;
+
+        } else if ("production" !== "development") {
+          console.error(
+            'Danger: Discarding unexpected node:',
+            renderNode
+          );
+        }
+      }
+    }
+
+    // Although resultList was populated out of order, it should now be a dense
+    // array.
+    ("production" !== "development" ? invariant(
+      resultListAssignmentCount === resultList.length,
+      'Danger: Did not assign to every index of resultList.'
+    ) : invariant(resultListAssignmentCount === resultList.length));
+
+    ("production" !== "development" ? invariant(
+      resultList.length === markupList.length,
+      'Danger: Expected markup to render %s nodes, but rendered %s.',
+      markupList.length,
+      resultList.length
+    ) : invariant(resultList.length === markupList.length));
+
+    return resultList;
+  },
+
+  /**
+   * Replaces a node with a string of markup at its current position within its
+   * parent. The markup must render into a single root node.
+   *
+   * @param {DOMElement} oldChild Child node to replace.
+   * @param {string} markup Markup to render in place of the child node.
+   * @internal
+   */
+  dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {
+    ("production" !== "development" ? invariant(
+      ExecutionEnvironment.canUseDOM,
+      'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +
+      'worker thread. Make sure `window` and `document` are available ' +
+      'globally before requiring React when unit testing or use ' +
+      'React.renderToString for server rendering.'
+    ) : invariant(ExecutionEnvironment.canUseDOM));
+    ("production" !== "development" ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
+    ("production" !== "development" ? invariant(
+      oldChild.tagName.toLowerCase() !== 'html',
+      'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
+      '<html> node. This is because browser quirks make this unreliable ' +
+      'and/or slow. If you want to render to the root you must use ' +
+      'server rendering. See React.renderToString().'
+    ) : invariant(oldChild.tagName.toLowerCase() !== 'html'));
+
+    var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
+    oldChild.parentNode.replaceChild(newChild, oldChild);
+  }
+
+};
+
+module.exports = Danger;
+
+},{"112":112,"114":114,"127":127,"135":135,"21":21}],13:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DefaultEventPluginOrder
+ */
+
+'use strict';
+
+var keyOf = _dereq_(141);
+
+/**
+ * Module that is injectable into `EventPluginHub`, that specifies a
+ * deterministic ordering of `EventPlugin`s. A convenient way to reason about
+ * plugins, without having to package every one of them. This is better than
+ * having plugins be ordered in the same order that they are injected because
+ * that ordering would be influenced by the packaging order.
+ * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
+ * preventing default on events is convenient in `SimpleEventPlugin` handlers.
+ */
+var DefaultEventPluginOrder = [
+  keyOf({ResponderEventPlugin: null}),
+  keyOf({SimpleEventPlugin: null}),
+  keyOf({TapEventPlugin: null}),
+  keyOf({EnterLeaveEventPlugin: null}),
+  keyOf({ChangeEventPlugin: null}),
+  keyOf({SelectEventPlugin: null}),
+  keyOf({BeforeInputEventPlugin: null}),
+  keyOf({AnalyticsEventPlugin: null}),
+  keyOf({MobileSafariClickEventPlugin: null})
+];
+
+module.exports = DefaultEventPluginOrder;
+
+},{"141":141}],14:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EnterLeaveEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPropagators = _dereq_(20);
+var SyntheticMouseEvent = _dereq_(99);
+
+var ReactMount = _dereq_(70);
+var keyOf = _dereq_(141);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var getFirstReactDOM = ReactMount.getFirstReactDOM;
+
+var eventTypes = {
+  mouseEnter: {
+    registrationName: keyOf({onMouseEnter: null}),
+    dependencies: [
+      topLevelTypes.topMouseOut,
+      topLevelTypes.topMouseOver
+    ]
+  },
+  mouseLeave: {
+    registrationName: keyOf({onMouseLeave: null}),
+    dependencies: [
+      topLevelTypes.topMouseOut,
+      topLevelTypes.topMouseOver
+    ]
+  }
+};
+
+var extractedEvents = [null, null];
+
+var EnterLeaveEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * For almost every interaction we care about, there will be both a top-level
+   * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
+   * we do not extract duplicate events. However, moving the mouse into the
+   * browser from outside will not fire a `mouseout` event. In this case, we use
+   * the `mouseover` top-level event.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    if (topLevelType === topLevelTypes.topMouseOver &&
+        (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
+      return null;
+    }
+    if (topLevelType !== topLevelTypes.topMouseOut &&
+        topLevelType !== topLevelTypes.topMouseOver) {
+      // Must not be a mouse in or mouse out - ignoring.
+      return null;
+    }
+
+    var win;
+    if (topLevelTarget.window === topLevelTarget) {
+      // `topLevelTarget` is probably a window object.
+      win = topLevelTarget;
+    } else {
+      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+      var doc = topLevelTarget.ownerDocument;
+      if (doc) {
+        win = doc.defaultView || doc.parentWindow;
+      } else {
+        win = window;
+      }
+    }
+
+    var from, to;
+    if (topLevelType === topLevelTypes.topMouseOut) {
+      from = topLevelTarget;
+      to =
+        getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
+        win;
+    } else {
+      from = win;
+      to = topLevelTarget;
+    }
+
+    if (from === to) {
+      // Nothing pertains to our managed components.
+      return null;
+    }
+
+    var fromID = from ? ReactMount.getID(from) : '';
+    var toID = to ? ReactMount.getID(to) : '';
+
+    var leave = SyntheticMouseEvent.getPooled(
+      eventTypes.mouseLeave,
+      fromID,
+      nativeEvent
+    );
+    leave.type = 'mouseleave';
+    leave.target = from;
+    leave.relatedTarget = to;
+
+    var enter = SyntheticMouseEvent.getPooled(
+      eventTypes.mouseEnter,
+      toID,
+      nativeEvent
+    );
+    enter.type = 'mouseenter';
+    enter.target = to;
+    enter.relatedTarget = from;
+
+    EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
+
+    extractedEvents[0] = leave;
+    extractedEvents[1] = enter;
+
+    return extractedEvents;
+  }
+
+};
+
+module.exports = EnterLeaveEventPlugin;
+
+},{"141":141,"15":15,"20":20,"70":70,"99":99}],15:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventConstants
+ */
+
+'use strict';
+
+var keyMirror = _dereq_(140);
+
+var PropagationPhases = keyMirror({bubbled: null, captured: null});
+
+/**
+ * Types of raw signals from the browser caught at the top level.
+ */
+var topLevelTypes = keyMirror({
+  topBlur: null,
+  topChange: null,
+  topClick: null,
+  topCompositionEnd: null,
+  topCompositionStart: null,
+  topCompositionUpdate: null,
+  topContextMenu: null,
+  topCopy: null,
+  topCut: null,
+  topDoubleClick: null,
+  topDrag: null,
+  topDragEnd: null,
+  topDragEnter: null,
+  topDragExit: null,
+  topDragLeave: null,
+  topDragOver: null,
+  topDragStart: null,
+  topDrop: null,
+  topError: null,
+  topFocus: null,
+  topInput: null,
+  topKeyDown: null,
+  topKeyPress: null,
+  topKeyUp: null,
+  topLoad: null,
+  topMouseDown: null,
+  topMouseMove: null,
+  topMouseOut: null,
+  topMouseOver: null,
+  topMouseUp: null,
+  topPaste: null,
+  topReset: null,
+  topScroll: null,
+  topSelectionChange: null,
+  topSubmit: null,
+  topTextInput: null,
+  topTouchCancel: null,
+  topTouchEnd: null,
+  topTouchMove: null,
+  topTouchStart: null,
+  topWheel: null
+});
+
+var EventConstants = {
+  topLevelTypes: topLevelTypes,
+  PropagationPhases: PropagationPhases
+};
+
+module.exports = EventConstants;
+
+},{"140":140}],16:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventListener
+ * @typechecks
+ */
+
+var emptyFunction = _dereq_(114);
+
+/**
+ * Upstream version of event listener. Does not take into account specific
+ * nature of platform.
+ */
+var EventListener = {
+  /**
+   * Listen to DOM events during the bubble phase.
+   *
+   * @param {DOMEventTarget} target DOM element to register listener on.
+   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+   * @param {function} callback Callback function.
+   * @return {object} Object with a `remove` method.
+   */
+  listen: function(target, eventType, callback) {
+    if (target.addEventListener) {
+      target.addEventListener(eventType, callback, false);
+      return {
+        remove: function() {
+          target.removeEventListener(eventType, callback, false);
+        }
+      };
+    } else if (target.attachEvent) {
+      target.attachEvent('on' + eventType, callback);
+      return {
+        remove: function() {
+          target.detachEvent('on' + eventType, callback);
+        }
+      };
+    }
+  },
+
+  /**
+   * Listen to DOM events during the capture phase.
+   *
+   * @param {DOMEventTarget} target DOM element to register listener on.
+   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+   * @param {function} callback Callback function.
+   * @return {object} Object with a `remove` method.
+   */
+  capture: function(target, eventType, callback) {
+    if (!target.addEventListener) {
+      if ("production" !== "development") {
+        console.error(
+          'Attempted to listen to events during the capture phase on a ' +
+          'browser that does not support the capture phase. Your application ' +
+          'will not receive some events.'
+        );
+      }
+      return {
+        remove: emptyFunction
+      };
+    } else {
+      target.addEventListener(eventType, callback, true);
+      return {
+        remove: function() {
+          target.removeEventListener(eventType, callback, true);
+        }
+      };
+    }
+  },
+
+  registerDefault: function() {}
+};
+
+module.exports = EventListener;
+
+},{"114":114}],17:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginHub
+ */
+
+'use strict';
+
+var EventPluginRegistry = _dereq_(18);
+var EventPluginUtils = _dereq_(19);
+
+var accumulateInto = _dereq_(105);
+var forEachAccumulated = _dereq_(120);
+var invariant = _dereq_(135);
+
+/**
+ * Internal store for event listeners
+ */
+var listenerBank = {};
+
+/**
+ * Internal queue of events that have accumulated their dispatches and are
+ * waiting to have their dispatches executed.
+ */
+var eventQueue = null;
+
+/**
+ * Dispatches an event and releases it back into the pool, unless persistent.
+ *
+ * @param {?object} event Synthetic event to be dispatched.
+ * @private
+ */
+var executeDispatchesAndRelease = function(event) {
+  if (event) {
+    var executeDispatch = EventPluginUtils.executeDispatch;
+    // Plugins can provide custom behavior when dispatching events.
+    var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
+    if (PluginModule && PluginModule.executeDispatch) {
+      executeDispatch = PluginModule.executeDispatch;
+    }
+    EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
+
+    if (!event.isPersistent()) {
+      event.constructor.release(event);
+    }
+  }
+};
+
+/**
+ * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
+ *   hierarchy given ids of the logical DOM elements involved.
+ */
+var InstanceHandle = null;
+
+function validateInstanceHandle() {
+  var valid =
+    InstanceHandle &&
+    InstanceHandle.traverseTwoPhase &&
+    InstanceHandle.traverseEnterLeave;
+  ("production" !== "development" ? invariant(
+    valid,
+    'InstanceHandle not injected before use!'
+  ) : invariant(valid));
+}
+
+/**
+ * This is a unified interface for event plugins to be installed and configured.
+ *
+ * Event plugins can implement the following properties:
+ *
+ *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
+ *     Required. When a top-level event is fired, this method is expected to
+ *     extract synthetic events that will in turn be queued and dispatched.
+ *
+ *   `eventTypes` {object}
+ *     Optional, plugins that fire events must publish a mapping of registration
+ *     names that are used to register listeners. Values of this mapping must
+ *     be objects that contain `registrationName` or `phasedRegistrationNames`.
+ *
+ *   `executeDispatch` {function(object, function, string)}
+ *     Optional, allows plugins to override how an event gets dispatched. By
+ *     default, the listener is simply invoked.
+ *
+ * Each plugin that is injected into `EventsPluginHub` is immediately operable.
+ *
+ * @public
+ */
+var EventPluginHub = {
+
+  /**
+   * Methods for injecting dependencies.
+   */
+  injection: {
+
+    /**
+     * @param {object} InjectedMount
+     * @public
+     */
+    injectMount: EventPluginUtils.injection.injectMount,
+
+    /**
+     * @param {object} InjectedInstanceHandle
+     * @public
+     */
+    injectInstanceHandle: function(InjectedInstanceHandle) {
+      InstanceHandle = InjectedInstanceHandle;
+      if ("production" !== "development") {
+        validateInstanceHandle();
+      }
+    },
+
+    getInstanceHandle: function() {
+      if ("production" !== "development") {
+        validateInstanceHandle();
+      }
+      return InstanceHandle;
+    },
+
+    /**
+     * @param {array} InjectedEventPluginOrder
+     * @public
+     */
+    injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
+
+    /**
+     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+     */
+    injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
+
+  },
+
+  eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
+
+  registrationNameModules: EventPluginRegistry.registrationNameModules,
+
+  /**
+   * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
+   *
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @param {?function} listener The callback to store.
+   */
+  putListener: function(id, registrationName, listener) {
+    ("production" !== "development" ? invariant(
+      !listener || typeof listener === 'function',
+      'Expected %s listener to be a function, instead got type %s',
+      registrationName, typeof listener
+    ) : invariant(!listener || typeof listener === 'function'));
+
+    var bankForRegistrationName =
+      listenerBank[registrationName] || (listenerBank[registrationName] = {});
+    bankForRegistrationName[id] = listener;
+  },
+
+  /**
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @return {?function} The stored callback.
+   */
+  getListener: function(id, registrationName) {
+    var bankForRegistrationName = listenerBank[registrationName];
+    return bankForRegistrationName && bankForRegistrationName[id];
+  },
+
+  /**
+   * Deletes a listener from the registration bank.
+   *
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   */
+  deleteListener: function(id, registrationName) {
+    var bankForRegistrationName = listenerBank[registrationName];
+    if (bankForRegistrationName) {
+      delete bankForRegistrationName[id];
+    }
+  },
+
+  /**
+   * Deletes all listeners for the DOM element with the supplied ID.
+   *
+   * @param {string} id ID of the DOM element.
+   */
+  deleteAllListeners: function(id) {
+    for (var registrationName in listenerBank) {
+      delete listenerBank[registrationName][id];
+    }
+  },
+
+  /**
+   * Allows registered plugins an opportunity to extract events from top-level
+   * native browser events.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @internal
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var events;
+    var plugins = EventPluginRegistry.plugins;
+    for (var i = 0, l = plugins.length; i < l; i++) {
+      // Not every plugin in the ordering may be loaded at runtime.
+      var possiblePlugin = plugins[i];
+      if (possiblePlugin) {
+        var extractedEvents = possiblePlugin.extractEvents(
+          topLevelType,
+          topLevelTarget,
+          topLevelTargetID,
+          nativeEvent
+        );
+        if (extractedEvents) {
+          events = accumulateInto(events, extractedEvents);
+        }
+      }
+    }
+    return events;
+  },
+
+  /**
+   * Enqueues a synthetic event that should be dispatched when
+   * `processEventQueue` is invoked.
+   *
+   * @param {*} events An accumulation of synthetic events.
+   * @internal
+   */
+  enqueueEvents: function(events) {
+    if (events) {
+      eventQueue = accumulateInto(eventQueue, events);
+    }
+  },
+
+  /**
+   * Dispatches all synthetic events on the event queue.
+   *
+   * @internal
+   */
+  processEventQueue: function() {
+    // Set `eventQueue` to null before processing it so that we can tell if more
+    // events get enqueued while processing.
+    var processingEventQueue = eventQueue;
+    eventQueue = null;
+    forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
+    ("production" !== "development" ? invariant(
+      !eventQueue,
+      'processEventQueue(): Additional events were enqueued while processing ' +
+      'an event queue. Support for this has not yet been implemented.'
+    ) : invariant(!eventQueue));
+  },
+
+  /**
+   * These are needed for tests only. Do not use!
+   */
+  __purge: function() {
+    listenerBank = {};
+  },
+
+  __getListenerBank: function() {
+    return listenerBank;
+  }
+
+};
+
+module.exports = EventPluginHub;
+
+},{"105":105,"120":120,"135":135,"18":18,"19":19}],18:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginRegistry
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ * Injectable ordering of event plugins.
+ */
+var EventPluginOrder = null;
+
+/**
+ * Injectable mapping from names to event plugin modules.
+ */
+var namesToPlugins = {};
+
+/**
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
+ *
+ * @private
+ */
+function recomputePluginOrdering() {
+  if (!EventPluginOrder) {
+    // Wait until an `EventPluginOrder` is injected.
+    return;
+  }
+  for (var pluginName in namesToPlugins) {
+    var PluginModule = namesToPlugins[pluginName];
+    var pluginIndex = EventPluginOrder.indexOf(pluginName);
+    ("production" !== "development" ? invariant(
+      pluginIndex > -1,
+      'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
+      'the plugin ordering, `%s`.',
+      pluginName
+    ) : invariant(pluginIndex > -1));
+    if (EventPluginRegistry.plugins[pluginIndex]) {
+      continue;
+    }
+    ("production" !== "development" ? invariant(
+      PluginModule.extractEvents,
+      'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
+      'method, but `%s` does not.',
+      pluginName
+    ) : invariant(PluginModule.extractEvents));
+    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
+    var publishedEvents = PluginModule.eventTypes;
+    for (var eventName in publishedEvents) {
+      ("production" !== "development" ? invariant(
+        publishEventForPlugin(
+          publishedEvents[eventName],
+          PluginModule,
+          eventName
+        ),
+        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
+        eventName,
+        pluginName
+      ) : invariant(publishEventForPlugin(
+        publishedEvents[eventName],
+        PluginModule,
+        eventName
+      )));
+    }
+  }
+}
+
+/**
+ * Publishes an event so that it can be dispatched by the supplied plugin.
+ *
+ * @param {object} dispatchConfig Dispatch configuration for the event.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @return {boolean} True if the event was successfully published.
+ * @private
+ */
+function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
+  ("production" !== "development" ? invariant(
+    !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+    'event name, `%s`.',
+    eventName
+  ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName)));
+  EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
+
+  var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
+  if (phasedRegistrationNames) {
+    for (var phaseName in phasedRegistrationNames) {
+      if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
+        var phasedRegistrationName = phasedRegistrationNames[phaseName];
+        publishRegistrationName(
+          phasedRegistrationName,
+          PluginModule,
+          eventName
+        );
+      }
+    }
+    return true;
+  } else if (dispatchConfig.registrationName) {
+    publishRegistrationName(
+      dispatchConfig.registrationName,
+      PluginModule,
+      eventName
+    );
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Publishes a registration name that is used to identify dispatched events and
+ * can be used with `EventPluginHub.putListener` to register listeners.
+ *
+ * @param {string} registrationName Registration name to add.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @private
+ */
+function publishRegistrationName(registrationName, PluginModule, eventName) {
+  ("production" !== "development" ? invariant(
+    !EventPluginRegistry.registrationNameModules[registrationName],
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+    'registration name, `%s`.',
+    registrationName
+  ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
+  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
+  EventPluginRegistry.registrationNameDependencies[registrationName] =
+    PluginModule.eventTypes[eventName].dependencies;
+}
+
+/**
+ * Registers plugins so that they can extract and dispatch events.
+ *
+ * @see {EventPluginHub}
+ */
+var EventPluginRegistry = {
+
+  /**
+   * Ordered list of injected plugins.
+   */
+  plugins: [],
+
+  /**
+   * Mapping from event name to dispatch config
+   */
+  eventNameDispatchConfigs: {},
+
+  /**
+   * Mapping from registration name to plugin module
+   */
+  registrationNameModules: {},
+
+  /**
+   * Mapping from registration name to event name
+   */
+  registrationNameDependencies: {},
+
+  /**
+   * Injects an ordering of plugins (by plugin name). This allows the ordering
+   * to be decoupled from injection of the actual plugins so that ordering is
+   * always deterministic regardless of packaging, on-the-fly injection, etc.
+   *
+   * @param {array} InjectedEventPluginOrder
+   * @internal
+   * @see {EventPluginHub.injection.injectEventPluginOrder}
+   */
+  injectEventPluginOrder: function(InjectedEventPluginOrder) {
+    ("production" !== "development" ? invariant(
+      !EventPluginOrder,
+      'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
+      'once. You are likely trying to load more than one copy of React.'
+    ) : invariant(!EventPluginOrder));
+    // Clone the ordering so it cannot be dynamically mutated.
+    EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
+    recomputePluginOrdering();
+  },
+
+  /**
+   * Injects plugins to be used by `EventPluginHub`. The plugin names must be
+   * in the ordering injected by `injectEventPluginOrder`.
+   *
+   * Plugins can be injected as part of page initialization or on-the-fly.
+   *
+   * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+   * @internal
+   * @see {EventPluginHub.injection.injectEventPluginsByName}
+   */
+  injectEventPluginsByName: function(injectedNamesToPlugins) {
+    var isOrderingDirty = false;
+    for (var pluginName in injectedNamesToPlugins) {
+      if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
+        continue;
+      }
+      var PluginModule = injectedNamesToPlugins[pluginName];
+      if (!namesToPlugins.hasOwnProperty(pluginName) ||
+          namesToPlugins[pluginName] !== PluginModule) {
+        ("production" !== "development" ? invariant(
+          !namesToPlugins[pluginName],
+          'EventPluginRegistry: Cannot inject two different event plugins ' +
+          'using the same name, `%s`.',
+          pluginName
+        ) : invariant(!namesToPlugins[pluginName]));
+        namesToPlugins[pluginName] = PluginModule;
+        isOrderingDirty = true;
+      }
+    }
+    if (isOrderingDirty) {
+      recomputePluginOrdering();
+    }
+  },
+
+  /**
+   * Looks up the plugin for the supplied event.
+   *
+   * @param {object} event A synthetic event.
+   * @return {?object} The plugin that created the supplied event.
+   * @internal
+   */
+  getPluginModuleForEvent: function(event) {
+    var dispatchConfig = event.dispatchConfig;
+    if (dispatchConfig.registrationName) {
+      return EventPluginRegistry.registrationNameModules[
+        dispatchConfig.registrationName
+      ] || null;
+    }
+    for (var phase in dispatchConfig.phasedRegistrationNames) {
+      if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
+        continue;
+      }
+      var PluginModule = EventPluginRegistry.registrationNameModules[
+        dispatchConfig.phasedRegistrationNames[phase]
+      ];
+      if (PluginModule) {
+        return PluginModule;
+      }
+    }
+    return null;
+  },
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _resetEventPlugins: function() {
+    EventPluginOrder = null;
+    for (var pluginName in namesToPlugins) {
+      if (namesToPlugins.hasOwnProperty(pluginName)) {
+        delete namesToPlugins[pluginName];
+      }
+    }
+    EventPluginRegistry.plugins.length = 0;
+
+    var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
+    for (var eventName in eventNameDispatchConfigs) {
+      if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
+        delete eventNameDispatchConfigs[eventName];
+      }
+    }
+
+    var registrationNameModules = EventPluginRegistry.registrationNameModules;
+    for (var registrationName in registrationNameModules) {
+      if (registrationNameModules.hasOwnProperty(registrationName)) {
+        delete registrationNameModules[registrationName];
+      }
+    }
+  }
+
+};
+
+module.exports = EventPluginRegistry;
+
+},{"135":135}],19:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginUtils
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+
+var invariant = _dereq_(135);
+
+/**
+ * Injected dependencies:
+ */
+
+/**
+ * - `Mount`: [required] Module that can convert between React dom IDs and
+ *   actual node references.
+ */
+var injection = {
+  Mount: null,
+  injectMount: function(InjectedMount) {
+    injection.Mount = InjectedMount;
+    if ("production" !== "development") {
+      ("production" !== "development" ? invariant(
+        InjectedMount && InjectedMount.getNode,
+        'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
+        'is missing getNode.'
+      ) : invariant(InjectedMount && InjectedMount.getNode));
+    }
+  }
+};
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+function isEndish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseUp ||
+         topLevelType === topLevelTypes.topTouchEnd ||
+         topLevelType === topLevelTypes.topTouchCancel;
+}
+
+function isMoveish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseMove ||
+         topLevelType === topLevelTypes.topTouchMove;
+}
+function isStartish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseDown ||
+         topLevelType === topLevelTypes.topTouchStart;
+}
+
+
+var validateEventDispatches;
+if ("production" !== "development") {
+  validateEventDispatches = function(event) {
+    var dispatchListeners = event._dispatchListeners;
+    var dispatchIDs = event._dispatchIDs;
+
+    var listenersIsArr = Array.isArray(dispatchListeners);
+    var idsIsArr = Array.isArray(dispatchIDs);
+    var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
+    var listenersLen = listenersIsArr ?
+      dispatchListeners.length :
+      dispatchListeners ? 1 : 0;
+
+    ("production" !== "development" ? invariant(
+      idsIsArr === listenersIsArr && IDsLen === listenersLen,
+      'EventPluginUtils: Invalid `event`.'
+    ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
+  };
+}
+
+/**
+ * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
+ * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
+ * kept separate to conserve memory.
+ */
+function forEachEventDispatch(event, cb) {
+  var dispatchListeners = event._dispatchListeners;
+  var dispatchIDs = event._dispatchIDs;
+  if ("production" !== "development") {
+    validateEventDispatches(event);
+  }
+  if (Array.isArray(dispatchListeners)) {
+    for (var i = 0; i < dispatchListeners.length; i++) {
+      if (event.isPropagationStopped()) {
+        break;
+      }
+      // Listeners and IDs are two parallel arrays that are always in sync.
+      cb(event, dispatchListeners[i], dispatchIDs[i]);
+    }
+  } else if (dispatchListeners) {
+    cb(event, dispatchListeners, dispatchIDs);
+  }
+}
+
+/**
+ * Default implementation of PluginModule.executeDispatch().
+ * @param {SyntheticEvent} SyntheticEvent to handle
+ * @param {function} Application-level callback
+ * @param {string} domID DOM id to pass to the callback.
+ */
+function executeDispatch(event, listener, domID) {
+  event.currentTarget = injection.Mount.getNode(domID);
+  var returnValue = listener(event, domID);
+  event.currentTarget = null;
+  return returnValue;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches.
+ */
+function executeDispatchesInOrder(event, cb) {
+  forEachEventDispatch(event, cb);
+  event._dispatchListeners = null;
+  event._dispatchIDs = null;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches, but stops
+ * at the first dispatch execution returning true, and returns that id.
+ *
+ * @return id of the first dispatch execution who's listener returns true, or
+ * null if no listener returned true.
+ */
+function executeDispatchesInOrderStopAtTrueImpl(event) {
+  var dispatchListeners = event._dispatchListeners;
+  var dispatchIDs = event._dispatchIDs;
+  if ("production" !== "development") {
+    validateEventDispatches(event);
+  }
+  if (Array.isArray(dispatchListeners)) {
+    for (var i = 0; i < dispatchListeners.length; i++) {
+      if (event.isPropagationStopped()) {
+        break;
+      }
+      // Listeners and IDs are two parallel arrays that are always in sync.
+      if (dispatchListeners[i](event, dispatchIDs[i])) {
+        return dispatchIDs[i];
+      }
+    }
+  } else if (dispatchListeners) {
+    if (dispatchListeners(event, dispatchIDs)) {
+      return dispatchIDs;
+    }
+  }
+  return null;
+}
+
+/**
+ * @see executeDispatchesInOrderStopAtTrueImpl
+ */
+function executeDispatchesInOrderStopAtTrue(event) {
+  var ret = executeDispatchesInOrderStopAtTrueImpl(event);
+  event._dispatchIDs = null;
+  event._dispatchListeners = null;
+  return ret;
+}
+
+/**
+ * Execution of a "direct" dispatch - there must be at most one dispatch
+ * accumulated on the event or it is considered an error. It doesn't really make
+ * sense for an event with multiple dispatches (bubbled) to keep track of the
+ * return values at each dispatch execution, but it does tend to make sense when
+ * dealing with "direct" dispatches.
+ *
+ * @return The return value of executing the single dispatch.
+ */
+function executeDirectDispatch(event) {
+  if ("production" !== "development") {
+    validateEventDispatches(event);
+  }
+  var dispatchListener = event._dispatchListeners;
+  var dispatchID = event._dispatchIDs;
+  ("production" !== "development" ? invariant(
+    !Array.isArray(dispatchListener),
+    'executeDirectDispatch(...): Invalid `event`.'
+  ) : invariant(!Array.isArray(dispatchListener)));
+  var res = dispatchListener ?
+    dispatchListener(event, dispatchID) :
+    null;
+  event._dispatchListeners = null;
+  event._dispatchIDs = null;
+  return res;
+}
+
+/**
+ * @param {SyntheticEvent} event
+ * @return {bool} True iff number of dispatches accumulated is greater than 0.
+ */
+function hasDispatches(event) {
+  return !!event._dispatchListeners;
+}
+
+/**
+ * General utilities that are useful in creating custom Event Plugins.
+ */
+var EventPluginUtils = {
+  isEndish: isEndish,
+  isMoveish: isMoveish,
+  isStartish: isStartish,
+
+  executeDirectDispatch: executeDirectDispatch,
+  executeDispatch: executeDispatch,
+  executeDispatchesInOrder: executeDispatchesInOrder,
+  executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
+  hasDispatches: hasDispatches,
+  injection: injection,
+  useTouchEvents: false
+};
+
+module.exports = EventPluginUtils;
+
+},{"135":135,"15":15}],20:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPropagators
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPluginHub = _dereq_(17);
+
+var accumulateInto = _dereq_(105);
+var forEachAccumulated = _dereq_(120);
+
+var PropagationPhases = EventConstants.PropagationPhases;
+var getListener = EventPluginHub.getListener;
+
+/**
+ * Some event types have a notion of different registration names for different
+ * "phases" of propagation. This finds listeners by a given phase.
+ */
+function listenerAtPhase(id, event, propagationPhase) {
+  var registrationName =
+    event.dispatchConfig.phasedRegistrationNames[propagationPhase];
+  return getListener(id, registrationName);
+}
+
+/**
+ * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
+ * here, allows us to not have to bind or create functions for each event.
+ * Mutating the event's members allows us to not have to create a wrapping
+ * "dispatch" object that pairs the event with the listener.
+ */
+function accumulateDirectionalDispatches(domID, upwards, event) {
+  if ("production" !== "development") {
+    if (!domID) {
+      throw new Error('Dispatching id must not be null');
+    }
+  }
+  var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
+  var listener = listenerAtPhase(domID, event, phase);
+  if (listener) {
+    event._dispatchListeners =
+      accumulateInto(event._dispatchListeners, listener);
+    event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
+  }
+}
+
+/**
+ * Collect dispatches (must be entirely collected before dispatching - see unit
+ * tests). Lazily allocate the array to conserve memory.  We must loop through
+ * each event and perform the traversal for each one. We can not perform a
+ * single traversal for the entire collection of events because each event may
+ * have a different target.
+ */
+function accumulateTwoPhaseDispatchesSingle(event) {
+  if (event && event.dispatchConfig.phasedRegistrationNames) {
+    EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
+      event.dispatchMarker,
+      accumulateDirectionalDispatches,
+      event
+    );
+  }
+}
+
+
+/**
+ * Accumulates without regard to direction, does not look for phased
+ * registration names. Same as `accumulateDirectDispatchesSingle` but without
+ * requiring that the `dispatchMarker` be the same as the dispatched ID.
+ */
+function accumulateDispatches(id, ignoredDirection, event) {
+  if (event && event.dispatchConfig.registrationName) {
+    var registrationName = event.dispatchConfig.registrationName;
+    var listener = getListener(id, registrationName);
+    if (listener) {
+      event._dispatchListeners =
+        accumulateInto(event._dispatchListeners, listener);
+      event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
+    }
+  }
+}
+
+/**
+ * Accumulates dispatches on an `SyntheticEvent`, but only for the
+ * `dispatchMarker`.
+ * @param {SyntheticEvent} event
+ */
+function accumulateDirectDispatchesSingle(event) {
+  if (event && event.dispatchConfig.registrationName) {
+    accumulateDispatches(event.dispatchMarker, null, event);
+  }
+}
+
+function accumulateTwoPhaseDispatches(events) {
+  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
+}
+
+function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
+  EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
+    fromID,
+    toID,
+    accumulateDispatches,
+    leave,
+    enter
+  );
+}
+
+
+function accumulateDirectDispatches(events) {
+  forEachAccumulated(events, accumulateDirectDispatchesSingle);
+}
+
+
+
+/**
+ * A small set of propagation patterns, each of which will accept a small amount
+ * of information, and generate a set of "dispatch ready event objects" - which
+ * are sets of events that have already been annotated with a set of dispatched
+ * listener functions/ids. The API is designed this way to discourage these
+ * propagation strategies from actually executing the dispatches, since we
+ * always want to collect the entire set of dispatches before executing event a
+ * single one.
+ *
+ * @constructor EventPropagators
+ */
+var EventPropagators = {
+  accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
+  accumulateDirectDispatches: accumulateDirectDispatches,
+  accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
+};
+
+module.exports = EventPropagators;
+
+},{"105":105,"120":120,"15":15,"17":17}],21:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ExecutionEnvironment
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var canUseDOM = !!(
+  (typeof window !== 'undefined' &&
+  window.document && window.document.createElement)
+);
+
+/**
+ * Simple, lightweight module assisting with the detection and context of
+ * Worker. Helps avoid circular dependencies and allows code to reason about
+ * whether or not they are in a Worker, even if they never include the main
+ * `ReactWorker` dependency.
+ */
+var ExecutionEnvironment = {
+
+  canUseDOM: canUseDOM,
+
+  canUseWorkers: typeof Worker !== 'undefined',
+
+  canUseEventListeners:
+    canUseDOM && !!(window.addEventListener || window.attachEvent),
+
+  canUseViewport: canUseDOM && !!window.screen,
+
+  isInWorker: !canUseDOM // For now, this is true - might change in the future.
+
+};
+
+module.exports = ExecutionEnvironment;
+
+},{}],22:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule FallbackCompositionState
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+
+var assign = _dereq_(27);
+var getTextContentAccessor = _dereq_(130);
+
+/**
+ * This helper class stores information about text content of a target node,
+ * allowing comparison of content before and after a given event.
+ *
+ * Identify the node where selection currently begins, then observe
+ * both its text content and its current position in the DOM. Since the
+ * browser may natively replace the target node during composition, we can
+ * use its position to find its replacement.
+ *
+ * @param {DOMEventTarget} root
+ */
+function FallbackCompositionState(root) {
+  this._root = root;
+  this._startText = this.getText();
+  this._fallbackText = null;
+}
+
+assign(FallbackCompositionState.prototype, {
+  /**
+   * Get current text of input.
+   *
+   * @return {string}
+   */
+  getText: function() {
+    if ('value' in this._root) {
+      return this._root.value;
+    }
+    return this._root[getTextContentAccessor()];
+  },
+
+  /**
+   * Determine the differing substring between the initially stored
+   * text content and the current content.
+   *
+   * @return {string}
+   */
+  getData: function() {
+    if (this._fallbackText) {
+      return this._fallbackText;
+    }
+
+    var start;
+    var startValue = this._startText;
+    var startLength = startValue.length;
+    var end;
+    var endValue = this.getText();
+    var endLength = endValue.length;
+
+    for (start = 0; start < startLength; start++) {
+      if (startValue[start] !== endValue[start]) {
+        break;
+      }
+    }
+
+    var minEnd = startLength - start;
+    for (end = 1; end <= minEnd; end++) {
+      if (startValue[startLength - end] !== endValue[endLength - end]) {
+        break;
+      }
+    }
+
+    var sliceTail = end > 1 ? 1 - end : undefined;
+    this._fallbackText = endValue.slice(start, sliceTail);
+    return this._fallbackText;
+  }
+});
+
+PooledClass.addPoolingTo(FallbackCompositionState);
+
+module.exports = FallbackCompositionState;
+
+},{"130":130,"27":27,"28":28}],23:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule HTMLDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+var ExecutionEnvironment = _dereq_(21);
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
+var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
+var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
+var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
+var HAS_POSITIVE_NUMERIC_VALUE =
+  DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
+var HAS_OVERLOADED_BOOLEAN_VALUE =
+  DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
+
+var hasSVG;
+if (ExecutionEnvironment.canUseDOM) {
+  var implementation = document.implementation;
+  hasSVG = (
+    implementation &&
+    implementation.hasFeature &&
+    implementation.hasFeature(
+      'http://www.w3.org/TR/SVG11/feature#BasicStructure',
+      '1.1'
+    )
+  );
+}
+
+
+var HTMLDOMPropertyConfig = {
+  isCustomAttribute: RegExp.prototype.test.bind(
+    /^(data|aria)-[a-z_][a-z\d_.\-]*$/
+  ),
+  Properties: {
+    /**
+     * Standard Properties
+     */
+    accept: null,
+    acceptCharset: null,
+    accessKey: null,
+    action: null,
+    allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    allowTransparency: MUST_USE_ATTRIBUTE,
+    alt: null,
+    async: HAS_BOOLEAN_VALUE,
+    autoComplete: null,
+    // autoFocus is polyfilled/normalized by AutoFocusMixin
+    // autoFocus: HAS_BOOLEAN_VALUE,
+    autoPlay: HAS_BOOLEAN_VALUE,
+    cellPadding: null,
+    cellSpacing: null,
+    charSet: MUST_USE_ATTRIBUTE,
+    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    classID: MUST_USE_ATTRIBUTE,
+    // To set className on SVG elements, it's necessary to use .setAttribute;
+    // this works on HTML elements too in all browsers except IE8. Conveniently,
+    // IE8 doesn't support SVG and so we can simply use the attribute in
+    // browsers that support SVG and the property in browsers that don't,
+    // regardless of whether the element is HTML or SVG.
+    className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
+    cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    colSpan: null,
+    content: null,
+    contentEditable: null,
+    contextMenu: MUST_USE_ATTRIBUTE,
+    controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    coords: null,
+    crossOrigin: null,
+    data: null, // For `<object />` acts as `src`.
+    dateTime: MUST_USE_ATTRIBUTE,
+    defer: HAS_BOOLEAN_VALUE,
+    dir: null,
+    disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    download: HAS_OVERLOADED_BOOLEAN_VALUE,
+    draggable: null,
+    encType: null,
+    form: MUST_USE_ATTRIBUTE,
+    formAction: MUST_USE_ATTRIBUTE,
+    formEncType: MUST_USE_ATTRIBUTE,
+    formMethod: MUST_USE_ATTRIBUTE,
+    formNoValidate: HAS_BOOLEAN_VALUE,
+    formTarget: MUST_USE_ATTRIBUTE,
+    frameBorder: MUST_USE_ATTRIBUTE,
+    headers: null,
+    height: MUST_USE_ATTRIBUTE,
+    hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    href: null,
+    hrefLang: null,
+    htmlFor: null,
+    httpEquiv: null,
+    icon: null,
+    id: MUST_USE_PROPERTY,
+    label: null,
+    lang: null,
+    list: MUST_USE_ATTRIBUTE,
+    loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    manifest: MUST_USE_ATTRIBUTE,
+    marginHeight: null,
+    marginWidth: null,
+    max: null,
+    maxLength: MUST_USE_ATTRIBUTE,
+    media: MUST_USE_ATTRIBUTE,
+    mediaGroup: null,
+    method: null,
+    min: null,
+    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    name: null,
+    noValidate: HAS_BOOLEAN_VALUE,
+    open: HAS_BOOLEAN_VALUE,
+    pattern: null,
+    placeholder: null,
+    poster: null,
+    preload: null,
+    radioGroup: null,
+    readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    rel: null,
+    required: HAS_BOOLEAN_VALUE,
+    role: MUST_USE_ATTRIBUTE,
+    rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    rowSpan: null,
+    sandbox: null,
+    scope: null,
+    scrolling: null,
+    seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    shape: null,
+    size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    sizes: MUST_USE_ATTRIBUTE,
+    span: HAS_POSITIVE_NUMERIC_VALUE,
+    spellCheck: null,
+    src: null,
+    srcDoc: MUST_USE_PROPERTY,
+    srcSet: MUST_USE_ATTRIBUTE,
+    start: HAS_NUMERIC_VALUE,
+    step: null,
+    style: null,
+    tabIndex: null,
+    target: null,
+    title: null,
+    type: null,
+    useMap: null,
+    value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
+    width: MUST_USE_ATTRIBUTE,
+    wmode: MUST_USE_ATTRIBUTE,
+
+    /**
+     * Non-standard Properties
+     */
+    // autoCapitalize and autoCorrect are supported in Mobile Safari for
+    // keyboard hints.
+    autoCapitalize: null,
+    autoCorrect: null,
+    // itemProp, itemScope, itemType are for
+    // Microdata support. See http://schema.org/docs/gs.html
+    itemProp: MUST_USE_ATTRIBUTE,
+    itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    itemType: MUST_USE_ATTRIBUTE,
+    // itemID and itemRef are for Microdata support as well but
+    // only specified in the the WHATWG spec document. See
+    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
+    itemID: MUST_USE_ATTRIBUTE,
+    itemRef: MUST_USE_ATTRIBUTE,
+    // property is supported for OpenGraph in meta tags.
+    property: null
+  },
+  DOMAttributeNames: {
+    acceptCharset: 'accept-charset',
+    className: 'class',
+    htmlFor: 'for',
+    httpEquiv: 'http-equiv'
+  },
+  DOMPropertyNames: {
+    autoCapitalize: 'autocapitalize',
+    autoComplete: 'autocomplete',
+    autoCorrect: 'autocorrect',
+    autoFocus: 'autofocus',
+    autoPlay: 'autoplay',
+    // `encoding` is equivalent to `enctype`, IE8 lacks an `enctype` setter.
+    // http://www.w3.org/TR/html5/forms.html#dom-fs-encoding
+    encType: 'encoding',
+    hrefLang: 'hreflang',
+    radioGroup: 'radiogroup',
+    spellCheck: 'spellcheck',
+    srcDoc: 'srcdoc',
+    srcSet: 'srcset'
+  }
+};
+
+module.exports = HTMLDOMPropertyConfig;
+
+},{"10":10,"21":21}],24:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LinkedValueUtils
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactPropTypes = _dereq_(78);
+
+var invariant = _dereq_(135);
+
+var hasReadOnlyValue = {
+  'button': true,
+  'checkbox': true,
+  'image': true,
+  'hidden': true,
+  'radio': true,
+  'reset': true,
+  'submit': true
+};
+
+function _assertSingleLink(input) {
+  ("production" !== "development" ? invariant(
+    input.props.checkedLink == null || input.props.valueLink == null,
+    'Cannot provide a checkedLink and a valueLink. If you want to use ' +
+    'checkedLink, you probably don\'t want to use valueLink and vice versa.'
+  ) : invariant(input.props.checkedLink == null || input.props.valueLink == null));
+}
+function _assertValueLink(input) {
+  _assertSingleLink(input);
+  ("production" !== "development" ? invariant(
+    input.props.value == null && input.props.onChange == null,
+    'Cannot provide a valueLink and a value or onChange event. If you want ' +
+    'to use value or onChange, you probably don\'t want to use valueLink.'
+  ) : invariant(input.props.value == null && input.props.onChange == null));
+}
+
+function _assertCheckedLink(input) {
+  _assertSingleLink(input);
+  ("production" !== "development" ? invariant(
+    input.props.checked == null && input.props.onChange == null,
+    'Cannot provide a checkedLink and a checked property or onChange event. ' +
+    'If you want to use checked or onChange, you probably don\'t want to ' +
+    'use checkedLink'
+  ) : invariant(input.props.checked == null && input.props.onChange == null));
+}
+
+/**
+ * @param {SyntheticEvent} e change event to handle
+ */
+function _handleLinkedValueChange(e) {
+  /*jshint validthis:true */
+  this.props.valueLink.requestChange(e.target.value);
+}
+
+/**
+  * @param {SyntheticEvent} e change event to handle
+  */
+function _handleLinkedCheckChange(e) {
+  /*jshint validthis:true */
+  this.props.checkedLink.requestChange(e.target.checked);
+}
+
+/**
+ * Provide a linked `value` attribute for controlled forms. You should not use
+ * this outside of the ReactDOM controlled form components.
+ */
+var LinkedValueUtils = {
+  Mixin: {
+    propTypes: {
+      value: function(props, propName, componentName) {
+        if (!props[propName] ||
+            hasReadOnlyValue[props.type] ||
+            props.onChange ||
+            props.readOnly ||
+            props.disabled) {
+          return null;
+        }
+        return new Error(
+          'You provided a `value` prop to a form field without an ' +
+          '`onChange` handler. This will render a read-only field. If ' +
+          'the field should be mutable use `defaultValue`. Otherwise, ' +
+          'set either `onChange` or `readOnly`.'
+        );
+      },
+      checked: function(props, propName, componentName) {
+        if (!props[propName] ||
+            props.onChange ||
+            props.readOnly ||
+            props.disabled) {
+          return null;
+        }
+        return new Error(
+          'You provided a `checked` prop to a form field without an ' +
+          '`onChange` handler. This will render a read-only field. If ' +
+          'the field should be mutable use `defaultChecked`. Otherwise, ' +
+          'set either `onChange` or `readOnly`.'
+        );
+      },
+      onChange: ReactPropTypes.func
+    }
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {*} current value of the input either from value prop or link.
+   */
+  getValue: function(input) {
+    if (input.props.valueLink) {
+      _assertValueLink(input);
+      return input.props.valueLink.value;
+    }
+    return input.props.value;
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {*} current checked status of the input either from checked prop
+   *             or link.
+   */
+  getChecked: function(input) {
+    if (input.props.checkedLink) {
+      _assertCheckedLink(input);
+      return input.props.checkedLink.value;
+    }
+    return input.props.checked;
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {function} change callback either from onChange prop or link.
+   */
+  getOnChange: function(input) {
+    if (input.props.valueLink) {
+      _assertValueLink(input);
+      return _handleLinkedValueChange;
+    } else if (input.props.checkedLink) {
+      _assertCheckedLink(input);
+      return _handleLinkedCheckChange;
+    }
+    return input.props.onChange;
+  }
+};
+
+module.exports = LinkedValueUtils;
+
+},{"135":135,"78":78}],25:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LocalEventTrapMixin
+ */
+
+'use strict';
+
+var ReactBrowserEventEmitter = _dereq_(30);
+
+var accumulateInto = _dereq_(105);
+var forEachAccumulated = _dereq_(120);
+var invariant = _dereq_(135);
+
+function remove(event) {
+  event.remove();
+}
+
+var LocalEventTrapMixin = {
+  trapBubbledEvent:function(topLevelType, handlerBaseName) {
+    ("production" !== "development" ? invariant(this.isMounted(), 'Must be mounted to trap events') : invariant(this.isMounted()));
+    // If a component renders to null or if another component fatals and causes
+    // the state of the tree to be corrupted, `node` here can be null.
+    var node = this.getDOMNode();
+    ("production" !== "development" ? invariant(
+      node,
+      'LocalEventTrapMixin.trapBubbledEvent(...): Requires node to be rendered.'
+    ) : invariant(node));
+    var listener = ReactBrowserEventEmitter.trapBubbledEvent(
+      topLevelType,
+      handlerBaseName,
+      node
+    );
+    this._localEventListeners =
+      accumulateInto(this._localEventListeners, listener);
+  },
+
+  // trapCapturedEvent would look nearly identical. We don't implement that
+  // method because it isn't currently needed.
+
+  componentWillUnmount:function() {
+    if (this._localEventListeners) {
+      forEachAccumulated(this._localEventListeners, remove);
+    }
+  }
+};
+
+module.exports = LocalEventTrapMixin;
+
+},{"105":105,"120":120,"135":135,"30":30}],26:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule MobileSafariClickEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+
+var emptyFunction = _dereq_(114);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+/**
+ * Mobile Safari does not fire properly bubble click events on non-interactive
+ * elements, which means delegated click listeners do not fire. The workaround
+ * for this bug involves attaching an empty click listener on the target node.
+ *
+ * This particular plugin works around the bug by attaching an empty click
+ * listener on `touchstart` (which does fire on every element).
+ */
+var MobileSafariClickEventPlugin = {
+
+  eventTypes: null,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    if (topLevelType === topLevelTypes.topTouchStart) {
+      var target = nativeEvent.target;
+      if (target && !target.onclick) {
+        target.onclick = emptyFunction;
+      }
+    }
+  }
+
+};
+
+module.exports = MobileSafariClickEventPlugin;
+
+},{"114":114,"15":15}],27:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Object.assign
+ */
+
+// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
+
+'use strict';
+
+function assign(target, sources) {
+  if (target == null) {
+    throw new TypeError('Object.assign target cannot be null or undefined');
+  }
+
+  var to = Object(target);
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+  for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
+    var nextSource = arguments[nextIndex];
+    if (nextSource == null) {
+      continue;
+    }
+
+    var from = Object(nextSource);
+
+    // We don't currently support accessors nor proxies. Therefore this
+    // copy cannot throw. If we ever supported this then we must handle
+    // exceptions and side-effects. We don't support symbols so they won't
+    // be transferred.
+
+    for (var key in from) {
+      if (hasOwnProperty.call(from, key)) {
+        to[key] = from[key];
+      }
+    }
+  }
+
+  return to;
+}
+
+module.exports = assign;
+
+},{}],28:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule PooledClass
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ * Static poolers. Several custom versions for each potential number of
+ * arguments. A completely generic pooler is easy to implement, but would
+ * require accessing the `arguments` object. In each of these, `this` refers to
+ * the Class itself, not an instance. If any others are needed, simply add them
+ * here, or in their own files.
+ */
+var oneArgumentPooler = function(copyFieldsFrom) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, copyFieldsFrom);
+    return instance;
+  } else {
+    return new Klass(copyFieldsFrom);
+  }
+};
+
+var twoArgumentPooler = function(a1, a2) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2);
+    return instance;
+  } else {
+    return new Klass(a1, a2);
+  }
+};
+
+var threeArgumentPooler = function(a1, a2, a3) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2, a3);
+    return instance;
+  } else {
+    return new Klass(a1, a2, a3);
+  }
+};
+
+var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2, a3, a4, a5);
+    return instance;
+  } else {
+    return new Klass(a1, a2, a3, a4, a5);
+  }
+};
+
+var standardReleaser = function(instance) {
+  var Klass = this;
+  ("production" !== "development" ? invariant(
+    instance instanceof Klass,
+    'Trying to release an instance into a pool of a different type.'
+  ) : invariant(instance instanceof Klass));
+  if (instance.destructor) {
+    instance.destructor();
+  }
+  if (Klass.instancePool.length < Klass.poolSize) {
+    Klass.instancePool.push(instance);
+  }
+};
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+/**
+ * Augments `CopyConstructor` to be a poolable class, augmenting only the class
+ * itself (statically) not adding any prototypical fields. Any CopyConstructor
+ * you give this may have a `poolSize` property, and will look for a
+ * prototypical `destructor` on instances (optional).
+ *
+ * @param {Function} CopyConstructor Constructor that can be used to reset.
+ * @param {Function} pooler Customizable pooler.
+ */
+var addPoolingTo = function(CopyConstructor, pooler) {
+  var NewKlass = CopyConstructor;
+  NewKlass.instancePool = [];
+  NewKlass.getPooled = pooler || DEFAULT_POOLER;
+  if (!NewKlass.poolSize) {
+    NewKlass.poolSize = DEFAULT_POOL_SIZE;
+  }
+  NewKlass.release = standardReleaser;
+  return NewKlass;
+};
+
+var PooledClass = {
+  addPoolingTo: addPoolingTo,
+  oneArgumentPooler: oneArgumentPooler,
+  twoArgumentPooler: twoArgumentPooler,
+  threeArgumentPooler: threeArgumentPooler,
+  fiveArgumentPooler: fiveArgumentPooler
+};
+
+module.exports = PooledClass;
+
+},{"135":135}],29:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserComponentMixin
+ */
+
+'use strict';
+
+var findDOMNode = _dereq_(117);
+
+var ReactBrowserComponentMixin = {
+  /**
+   * Returns the DOM node rendered by this component.
+   *
+   * @return {DOMElement} The root node of this component.
+   * @final
+   * @protected
+   */
+  getDOMNode: function() {
+    return findDOMNode(this);
+  }
+};
+
+module.exports = ReactBrowserComponentMixin;
+
+},{"117":117}],30:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserEventEmitter
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPluginHub = _dereq_(17);
+var EventPluginRegistry = _dereq_(18);
+var ReactEventEmitterMixin = _dereq_(61);
+var ViewportMetrics = _dereq_(104);
+
+var assign = _dereq_(27);
+var isEventSupported = _dereq_(136);
+
+/**
+ * Summary of `ReactBrowserEventEmitter` event handling:
+ *
+ *  - Top-level delegation is used to trap most native browser events. This
+ *    may only occur in the main thread and is the responsibility of
+ *    ReactEventListener, which is injected and can therefore support pluggable
+ *    event sources. This is the only work that occurs in the main thread.
+ *
+ *  - We normalize and de-duplicate events to account for browser quirks. This
+ *    may be done in the worker thread.
+ *
+ *  - Forward these native events (with the associated top-level type used to
+ *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
+ *    to extract any synthetic events.
+ *
+ *  - The `EventPluginHub` will then process each event by annotating them with
+ *    "dispatches", a sequence of listeners and IDs that care about that event.
+ *
+ *  - The `EventPluginHub` then dispatches the events.
+ *
+ * Overview of React and the event system:
+ *
+ * +------------+    .
+ * |    DOM     |    .
+ * +------------+    .
+ *       |           .
+ *       v           .
+ * +------------+    .
+ * | ReactEvent |    .
+ * |  Listener  |    .
+ * +------------+    .                         +-----------+
+ *       |           .               +--------+|SimpleEvent|
+ *       |           .               |         |Plugin     |
+ * +-----|------+    .               v         +-----------+
+ * |     |      |    .    +--------------+                    +------------+
+ * |     +-----------.--->|EventPluginHub|                    |    Event   |
+ * |            |    .    |              |     +-----------+  | Propagators|
+ * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
+ * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
+ * |            |    .    |              |     +-----------+  |  utilities |
+ * |     +-----------.--->|              |                    +------------+
+ * |     |      |    .    +--------------+
+ * +-----|------+    .                ^        +-----------+
+ *       |           .                |        |Enter/Leave|
+ *       +           .                +-------+|Plugin     |
+ * +-------------+   .                         +-----------+
+ * | application |   .
+ * |-------------|   .
+ * |             |   .
+ * |             |   .
+ * +-------------+   .
+ *                   .
+ *    React Core     .  General Purpose Event Plugin System
+ */
+
+var alreadyListeningTo = {};
+var isMonitoringScrollValue = false;
+var reactTopListenersCounter = 0;
+
+// For events like 'submit' which don't consistently bubble (which we trap at a
+// lower node than `document`), binding at `document` would cause duplicate
+// events so we don't include them here
+var topEventMapping = {
+  topBlur: 'blur',
+  topChange: 'change',
+  topClick: 'click',
+  topCompositionEnd: 'compositionend',
+  topCompositionStart: 'compositionstart',
+  topCompositionUpdate: 'compositionupdate',
+  topContextMenu: 'contextmenu',
+  topCopy: 'copy',
+  topCut: 'cut',
+  topDoubleClick: 'dblclick',
+  topDrag: 'drag',
+  topDragEnd: 'dragend',
+  topDragEnter: 'dragenter',
+  topDragExit: 'dragexit',
+  topDragLeave: 'dragleave',
+  topDragOver: 'dragover',
+  topDragStart: 'dragstart',
+  topDrop: 'drop',
+  topFocus: 'focus',
+  topInput: 'input',
+  topKeyDown: 'keydown',
+  topKeyPress: 'keypress',
+  topKeyUp: 'keyup',
+  topMouseDown: 'mousedown',
+  topMouseMove: 'mousemove',
+  topMouseOut: 'mouseout',
+  topMouseOver: 'mouseover',
+  topMouseUp: 'mouseup',
+  topPaste: 'paste',
+  topScroll: 'scroll',
+  topSelectionChange: 'selectionchange',
+  topTextInput: 'textInput',
+  topTouchCancel: 'touchcancel',
+  topTouchEnd: 'touchend',
+  topTouchMove: 'touchmove',
+  topTouchStart: 'touchstart',
+  topWheel: 'wheel'
+};
+
+/**
+ * To ensure no conflicts with other potential React instances on the page
+ */
+var topListenersIDKey = '_reactListenersID' + String(Math.random()).slice(2);
+
+function getListeningForDocument(mountAt) {
+  // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
+  // directly.
+  if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
+    mountAt[topListenersIDKey] = reactTopListenersCounter++;
+    alreadyListeningTo[mountAt[topListenersIDKey]] = {};
+  }
+  return alreadyListeningTo[mountAt[topListenersIDKey]];
+}
+
+/**
+ * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
+ * example:
+ *
+ *   ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
+ *
+ * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
+ *
+ * @internal
+ */
+var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {
+
+  /**
+   * Injectable event backend
+   */
+  ReactEventListener: null,
+
+  injection: {
+    /**
+     * @param {object} ReactEventListener
+     */
+    injectReactEventListener: function(ReactEventListener) {
+      ReactEventListener.setHandleTopLevel(
+        ReactBrowserEventEmitter.handleTopLevel
+      );
+      ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
+    }
+  },
+
+  /**
+   * Sets whether or not any created callbacks should be enabled.
+   *
+   * @param {boolean} enabled True if callbacks should be enabled.
+   */
+  setEnabled: function(enabled) {
+    if (ReactBrowserEventEmitter.ReactEventListener) {
+      ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
+    }
+  },
+
+  /**
+   * @return {boolean} True if callbacks are enabled.
+   */
+  isEnabled: function() {
+    return !!(
+      (ReactBrowserEventEmitter.ReactEventListener && ReactBrowserEventEmitter.ReactEventListener.isEnabled())
+    );
+  },
+
+  /**
+   * We listen for bubbled touch events on the document object.
+   *
+   * Firefox v8.01 (and possibly others) exhibited strange behavior when
+   * mounting `onmousemove` events at some node that was not the document
+   * element. The symptoms were that if your mouse is not moving over something
+   * contained within that mount point (for example on the background) the
+   * top-level listeners for `onmousemove` won't be called. However, if you
+   * register the `mousemove` on the document object, then it will of course
+   * catch all `mousemove`s. This along with iOS quirks, justifies restricting
+   * top-level listeners to the document object only, at least for these
+   * movement types of events and possibly all events.
+   *
+   * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
+   *
+   * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
+   * they bubble to document.
+   *
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @param {object} contentDocumentHandle Document which owns the container
+   */
+  listenTo: function(registrationName, contentDocumentHandle) {
+    var mountAt = contentDocumentHandle;
+    var isListening = getListeningForDocument(mountAt);
+    var dependencies = EventPluginRegistry.
+      registrationNameDependencies[registrationName];
+
+    var topLevelTypes = EventConstants.topLevelTypes;
+    for (var i = 0, l = dependencies.length; i < l; i++) {
+      var dependency = dependencies[i];
+      if (!(
+            (isListening.hasOwnProperty(dependency) && isListening[dependency])
+          )) {
+        if (dependency === topLevelTypes.topWheel) {
+          if (isEventSupported('wheel')) {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'wheel',
+              mountAt
+            );
+          } else if (isEventSupported('mousewheel')) {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'mousewheel',
+              mountAt
+            );
+          } else {
+            // Firefox needs to capture a different mouse scroll event.
+            // @see http://www.quirksmode.org/dom/events/tests/scroll.html
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'DOMMouseScroll',
+              mountAt
+            );
+          }
+        } else if (dependency === topLevelTypes.topScroll) {
+
+          if (isEventSupported('scroll', true)) {
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topScroll,
+              'scroll',
+              mountAt
+            );
+          } else {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topScroll,
+              'scroll',
+              ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
+            );
+          }
+        } else if (dependency === topLevelTypes.topFocus ||
+            dependency === topLevelTypes.topBlur) {
+
+          if (isEventSupported('focus', true)) {
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topFocus,
+              'focus',
+              mountAt
+            );
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topBlur,
+              'blur',
+              mountAt
+            );
+          } else if (isEventSupported('focusin')) {
+            // IE has `focusin` and `focusout` events which bubble.
+            // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topFocus,
+              'focusin',
+              mountAt
+            );
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topBlur,
+              'focusout',
+              mountAt
+            );
+          }
+
+          // to make sure blur and focus event listeners are only attached once
+          isListening[topLevelTypes.topBlur] = true;
+          isListening[topLevelTypes.topFocus] = true;
+        } else if (topEventMapping.hasOwnProperty(dependency)) {
+          ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+            dependency,
+            topEventMapping[dependency],
+            mountAt
+          );
+        }
+
+        isListening[dependency] = true;
+      }
+    }
+  },
+
+  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+    return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+      topLevelType,
+      handlerBaseName,
+      handle
+    );
+  },
+
+  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+    return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+      topLevelType,
+      handlerBaseName,
+      handle
+    );
+  },
+
+  /**
+   * Listens to window scroll and resize events. We cache scroll values so that
+   * application code can access them without triggering reflows.
+   *
+   * NOTE: Scroll events do not bubble.
+   *
+   * @see http://www.quirksmode.org/dom/events/scroll.html
+   */
+  ensureScrollValueMonitoring: function() {
+    if (!isMonitoringScrollValue) {
+      var refresh = ViewportMetrics.refreshScrollValues;
+      ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
+      isMonitoringScrollValue = true;
+    }
+  },
+
+  eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
+
+  registrationNameModules: EventPluginHub.registrationNameModules,
+
+  putListener: EventPluginHub.putListener,
+
+  getListener: EventPluginHub.getListener,
+
+  deleteListener: EventPluginHub.deleteListener,
+
+  deleteAllListeners: EventPluginHub.deleteAllListeners
+
+});
+
+module.exports = ReactBrowserEventEmitter;
+
+},{"104":104,"136":136,"15":15,"17":17,"18":18,"27":27,"61":61}],31:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildReconciler
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactReconciler = _dereq_(81);
+
+var flattenChildren = _dereq_(118);
+var instantiateReactComponent = _dereq_(134);
+var shouldUpdateReactComponent = _dereq_(151);
+
+/**
+ * ReactChildReconciler provides helpers for initializing or updating a set of
+ * children. Its output is suitable for passing it onto ReactMultiChild which
+ * does diffed reordering and insertion.
+ */
+var ReactChildReconciler = {
+
+  /**
+   * Generates a "mount image" for each of the supplied children. In the case
+   * of `ReactDOMComponent`, a mount image is a string of markup.
+   *
+   * @param {?object} nestedChildNodes Nested child maps.
+   * @return {?object} A set of child instances.
+   * @internal
+   */
+  instantiateChildren: function(nestedChildNodes, transaction, context) {
+    var children = flattenChildren(nestedChildNodes);
+    for (var name in children) {
+      if (children.hasOwnProperty(name)) {
+        var child = children[name];
+        // The rendered children must be turned into instances as they're
+        // mounted.
+        var childInstance = instantiateReactComponent(child, null);
+        children[name] = childInstance;
+      }
+    }
+    return children;
+  },
+
+  /**
+   * Updates the rendered children and returns a new set of children.
+   *
+   * @param {?object} prevChildren Previously initialized set of children.
+   * @param {?object} nextNestedChildNodes Nested child maps.
+   * @param {ReactReconcileTransaction} transaction
+   * @param {object} context
+   * @return {?object} A new set of child instances.
+   * @internal
+   */
+  updateChildren: function(
+    prevChildren,
+    nextNestedChildNodes,
+    transaction,
+    context) {
+    // We currently don't have a way to track moves here but if we use iterators
+    // instead of for..in we can zip the iterators and check if an item has
+    // moved.
+    // TODO: If nothing has changed, return the prevChildren object so that we
+    // can quickly bailout if nothing has changed.
+    var nextChildren = flattenChildren(nextNestedChildNodes);
+    if (!nextChildren && !prevChildren) {
+      return null;
+    }
+    var name;
+    for (name in nextChildren) {
+      if (!nextChildren.hasOwnProperty(name)) {
+        continue;
+      }
+      var prevChild = prevChildren && prevChildren[name];
+      var prevElement = prevChild && prevChild._currentElement;
+      var nextElement = nextChildren[name];
+      if (shouldUpdateReactComponent(prevElement, nextElement)) {
+        ReactReconciler.receiveComponent(
+          prevChild, nextElement, transaction, context
+        );
+        nextChildren[name] = prevChild;
+      } else {
+        if (prevChild) {
+          ReactReconciler.unmountComponent(prevChild, name);
+        }
+        // The child must be instantiated before it's mounted.
+        var nextChildInstance = instantiateReactComponent(
+          nextElement,
+          null
+        );
+        nextChildren[name] = nextChildInstance;
+      }
+    }
+    // Unmount children that are no longer present.
+    for (name in prevChildren) {
+      if (prevChildren.hasOwnProperty(name) &&
+          !(nextChildren && nextChildren.hasOwnProperty(name))) {
+        ReactReconciler.unmountComponent(prevChildren[name]);
+      }
+    }
+    return nextChildren;
+  },
+
+  /**
+   * Unmounts all rendered children. This should be used to clean up children
+   * when this component is unmounted.
+   *
+   * @param {?object} renderedChildren Previously initialized set of children.
+   * @internal
+   */
+  unmountChildren: function(renderedChildren) {
+    for (var name in renderedChildren) {
+      var renderedChild = renderedChildren[name];
+      ReactReconciler.unmountComponent(renderedChild);
+    }
+  }
+
+};
+
+module.exports = ReactChildReconciler;
+
+},{"118":118,"134":134,"151":151,"81":81}],32:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildren
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+var ReactFragment = _dereq_(63);
+
+var traverseAllChildren = _dereq_(153);
+var warning = _dereq_(154);
+
+var twoArgumentPooler = PooledClass.twoArgumentPooler;
+var threeArgumentPooler = PooledClass.threeArgumentPooler;
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * traversal. Allows avoiding binding callbacks.
+ *
+ * @constructor ForEachBookKeeping
+ * @param {!function} forEachFunction Function to perform traversal with.
+ * @param {?*} forEachContext Context to perform context with.
+ */
+function ForEachBookKeeping(forEachFunction, forEachContext) {
+  this.forEachFunction = forEachFunction;
+  this.forEachContext = forEachContext;
+}
+PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
+
+function forEachSingleChild(traverseContext, child, name, i) {
+  var forEachBookKeeping = traverseContext;
+  forEachBookKeeping.forEachFunction.call(
+    forEachBookKeeping.forEachContext, child, i);
+}
+
+/**
+ * Iterates through children that are typically specified as `props.children`.
+ *
+ * The provided forEachFunc(child, index) will be called for each
+ * leaf child.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} forEachFunc.
+ * @param {*} forEachContext Context for forEachContext.
+ */
+function forEachChildren(children, forEachFunc, forEachContext) {
+  if (children == null) {
+    return children;
+  }
+
+  var traverseContext =
+    ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
+  traverseAllChildren(children, forEachSingleChild, traverseContext);
+  ForEachBookKeeping.release(traverseContext);
+}
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * mapping. Allows avoiding binding callbacks.
+ *
+ * @constructor MapBookKeeping
+ * @param {!*} mapResult Object containing the ordered map of results.
+ * @param {!function} mapFunction Function to perform mapping with.
+ * @param {?*} mapContext Context to perform mapping with.
+ */
+function MapBookKeeping(mapResult, mapFunction, mapContext) {
+  this.mapResult = mapResult;
+  this.mapFunction = mapFunction;
+  this.mapContext = mapContext;
+}
+PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
+
+function mapSingleChildIntoContext(traverseContext, child, name, i) {
+  var mapBookKeeping = traverseContext;
+  var mapResult = mapBookKeeping.mapResult;
+
+  var keyUnique = !mapResult.hasOwnProperty(name);
+  if ("production" !== "development") {
+    ("production" !== "development" ? warning(
+      keyUnique,
+      'ReactChildren.map(...): Encountered two children with the same key, ' +
+      '`%s`. Child keys must be unique; when two children share a key, only ' +
+      'the first child will be used.',
+      name
+    ) : null);
+  }
+
+  if (keyUnique) {
+    var mappedChild =
+      mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
+    mapResult[name] = mappedChild;
+  }
+}
+
+/**
+ * Maps children that are typically specified as `props.children`.
+ *
+ * The provided mapFunction(child, key, index) will be called for each
+ * leaf child.
+ *
+ * TODO: This may likely break any calls to `ReactChildren.map` that were
+ * previously relying on the fact that we guarded against null children.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} mapFunction.
+ * @param {*} mapContext Context for mapFunction.
+ * @return {object} Object containing the ordered map of results.
+ */
+function mapChildren(children, func, context) {
+  if (children == null) {
+    return children;
+  }
+
+  var mapResult = {};
+  var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
+  traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
+  MapBookKeeping.release(traverseContext);
+  return ReactFragment.create(mapResult);
+}
+
+function forEachSingleChildDummy(traverseContext, child, name, i) {
+  return null;
+}
+
+/**
+ * Count the number of children that are typically specified as
+ * `props.children`.
+ *
+ * @param {?*} children Children tree container.
+ * @return {number} The number of children.
+ */
+function countChildren(children, context) {
+  return traverseAllChildren(children, forEachSingleChildDummy, null);
+}
+
+var ReactChildren = {
+  forEach: forEachChildren,
+  map: mapChildren,
+  count: countChildren
+};
+
+module.exports = ReactChildren;
+
+},{"153":153,"154":154,"28":28,"63":63}],33:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactClass
+ */
+
+'use strict';
+
+var ReactComponent = _dereq_(34);
+var ReactCurrentOwner = _dereq_(39);
+var ReactElement = _dereq_(57);
+var ReactErrorUtils = _dereq_(60);
+var ReactInstanceMap = _dereq_(67);
+var ReactLifeCycle = _dereq_(68);
+var ReactPropTypeLocations = _dereq_(77);
+var ReactPropTypeLocationNames = _dereq_(76);
+var ReactUpdateQueue = _dereq_(86);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+var keyMirror = _dereq_(140);
+var keyOf = _dereq_(141);
+var warning = _dereq_(154);
+
+var MIXINS_KEY = keyOf({mixins: null});
+
+/**
+ * Policies that describe methods in `ReactClassInterface`.
+ */
+var SpecPolicy = keyMirror({
+  /**
+   * These methods may be defined only once by the class specification or mixin.
+   */
+  DEFINE_ONCE: null,
+  /**
+   * These methods may be defined by both the class specification and mixins.
+   * Subsequent definitions will be chained. These methods must return void.
+   */
+  DEFINE_MANY: null,
+  /**
+   * These methods are overriding the base class.
+   */
+  OVERRIDE_BASE: null,
+  /**
+   * These methods are similar to DEFINE_MANY, except we assume they return
+   * objects. We try to merge the keys of the return values of all the mixed in
+   * functions. If there is a key conflict we throw.
+   */
+  DEFINE_MANY_MERGED: null
+});
+
+
+var injectedMixins = [];
+
+/**
+ * Composite components are higher-level components that compose other composite
+ * or native components.
+ *
+ * To create a new type of `ReactClass`, pass a specification of
+ * your new class to `React.createClass`. The only requirement of your class
+ * specification is that you implement a `render` method.
+ *
+ *   var MyComponent = React.createClass({
+ *     render: function() {
+ *       return <div>Hello World</div>;
+ *     }
+ *   });
+ *
+ * The class specification supports a specific protocol of methods that have
+ * special meaning (e.g. `render`). See `ReactClassInterface` for
+ * more the comprehensive protocol. Any other properties and methods in the
+ * class specification will available on the prototype.
+ *
+ * @interface ReactClassInterface
+ * @internal
+ */
+var ReactClassInterface = {
+
+  /**
+   * An array of Mixin objects to include when defining your component.
+   *
+   * @type {array}
+   * @optional
+   */
+  mixins: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * An object containing properties and methods that should be defined on
+   * the component's constructor instead of its prototype (static methods).
+   *
+   * @type {object}
+   * @optional
+   */
+  statics: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of prop types for this component.
+   *
+   * @type {object}
+   * @optional
+   */
+  propTypes: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of context types for this component.
+   *
+   * @type {object}
+   * @optional
+   */
+  contextTypes: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of context types this component sets for its children.
+   *
+   * @type {object}
+   * @optional
+   */
+  childContextTypes: SpecPolicy.DEFINE_MANY,
+
+  // ==== Definition methods ====
+
+  /**
+   * Invoked when the component is mounted. Values in the mapping will be set on
+   * `this.props` if that prop is not specified (i.e. using an `in` check).
+   *
+   * This method is invoked before `getInitialState` and therefore cannot rely
+   * on `this.state` or use `this.setState`.
+   *
+   * @return {object}
+   * @optional
+   */
+  getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * Invoked once before the component is mounted. The return value will be used
+   * as the initial value of `this.state`.
+   *
+   *   getInitialState: function() {
+   *     return {
+   *       isOn: false,
+   *       fooBaz: new BazFoo()
+   *     }
+   *   }
+   *
+   * @return {object}
+   * @optional
+   */
+  getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * @return {object}
+   * @optional
+   */
+  getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * Uses props from `this.props` and state from `this.state` to render the
+   * structure of the component.
+   *
+   * No guarantees are made about when or how often this method is invoked, so
+   * it must not have side effects.
+   *
+   *   render: function() {
+   *     var name = this.props.name;
+   *     return <div>Hello, {name}!</div>;
+   *   }
+   *
+   * @return {ReactComponent}
+   * @nosideeffects
+   * @required
+   */
+  render: SpecPolicy.DEFINE_ONCE,
+
+
+
+  // ==== Delegate methods ====
+
+  /**
+   * Invoked when the component is initially created and about to be mounted.
+   * This may have side effects, but any external subscriptions or data created
+   * by this method must be cleaned up in `componentWillUnmount`.
+   *
+   * @optional
+   */
+  componentWillMount: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component has been mounted and has a DOM representation.
+   * However, there is no guarantee that the DOM node is in the document.
+   *
+   * Use this as an opportunity to operate on the DOM when the component has
+   * been mounted (initialized and rendered) for the first time.
+   *
+   * @param {DOMElement} rootNode DOM element representing the component.
+   * @optional
+   */
+  componentDidMount: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked before the component receives new props.
+   *
+   * Use this as an opportunity to react to a prop transition by updating the
+   * state using `this.setState`. Current props are accessed via `this.props`.
+   *
+   *   componentWillReceiveProps: function(nextProps, nextContext) {
+   *     this.setState({
+   *       likesIncreasing: nextProps.likeCount > this.props.likeCount
+   *     });
+   *   }
+   *
+   * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
+   * transition may cause a state change, but the opposite is not true. If you
+   * need it, you are probably looking for `componentWillUpdate`.
+   *
+   * @param {object} nextProps
+   * @optional
+   */
+  componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked while deciding if the component should be updated as a result of
+   * receiving new props, state and/or context.
+   *
+   * Use this as an opportunity to `return false` when you're certain that the
+   * transition to the new props/state/context will not require a component
+   * update.
+   *
+   *   shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+   *     return !equal(nextProps, this.props) ||
+   *       !equal(nextState, this.state) ||
+   *       !equal(nextContext, this.context);
+   *   }
+   *
+   * @param {object} nextProps
+   * @param {?object} nextState
+   * @param {?object} nextContext
+   * @return {boolean} True if the component should update.
+   * @optional
+   */
+  shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
+
+  /**
+   * Invoked when the component is about to update due to a transition from
+   * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
+   * and `nextContext`.
+   *
+   * Use this as an opportunity to perform preparation before an update occurs.
+   *
+   * NOTE: You **cannot** use `this.setState()` in this method.
+   *
+   * @param {object} nextProps
+   * @param {?object} nextState
+   * @param {?object} nextContext
+   * @param {ReactReconcileTransaction} transaction
+   * @optional
+   */
+  componentWillUpdate: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component's DOM representation has been updated.
+   *
+   * Use this as an opportunity to operate on the DOM when the component has
+   * been updated.
+   *
+   * @param {object} prevProps
+   * @param {?object} prevState
+   * @param {?object} prevContext
+   * @param {DOMElement} rootNode DOM element representing the component.
+   * @optional
+   */
+  componentDidUpdate: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component is about to be removed from its parent and have
+   * its DOM representation destroyed.
+   *
+   * Use this as an opportunity to deallocate any external resources.
+   *
+   * NOTE: There is no `componentDidUnmount` since your component will have been
+   * destroyed by that point.
+   *
+   * @optional
+   */
+  componentWillUnmount: SpecPolicy.DEFINE_MANY,
+
+
+
+  // ==== Advanced methods ====
+
+  /**
+   * Updates the component's currently mounted DOM representation.
+   *
+   * By default, this implements React's rendering and reconciliation algorithm.
+   * Sophisticated clients may wish to override this.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   * @overridable
+   */
+  updateComponent: SpecPolicy.OVERRIDE_BASE
+
+};
+
+/**
+ * Mapping from class specification keys to special processing functions.
+ *
+ * Although these are declared like instance properties in the specification
+ * when defining classes using `React.createClass`, they are actually static
+ * and are accessible on the constructor instead of the prototype. Despite
+ * being static, they must be defined outside of the "statics" key under
+ * which all other static methods are defined.
+ */
+var RESERVED_SPEC_KEYS = {
+  displayName: function(Constructor, displayName) {
+    Constructor.displayName = displayName;
+  },
+  mixins: function(Constructor, mixins) {
+    if (mixins) {
+      for (var i = 0; i < mixins.length; i++) {
+        mixSpecIntoComponent(Constructor, mixins[i]);
+      }
+    }
+  },
+  childContextTypes: function(Constructor, childContextTypes) {
+    if ("production" !== "development") {
+      validateTypeDef(
+        Constructor,
+        childContextTypes,
+        ReactPropTypeLocations.childContext
+      );
+    }
+    Constructor.childContextTypes = assign(
+      {},
+      Constructor.childContextTypes,
+      childContextTypes
+    );
+  },
+  contextTypes: function(Constructor, contextTypes) {
+    if ("production" !== "development") {
+      validateTypeDef(
+        Constructor,
+        contextTypes,
+        ReactPropTypeLocations.context
+      );
+    }
+    Constructor.contextTypes = assign(
+      {},
+      Constructor.contextTypes,
+      contextTypes
+    );
+  },
+  /**
+   * Special case getDefaultProps which should move into statics but requires
+   * automatic merging.
+   */
+  getDefaultProps: function(Constructor, getDefaultProps) {
+    if (Constructor.getDefaultProps) {
+      Constructor.getDefaultProps = createMergedResultFunction(
+        Constructor.getDefaultProps,
+        getDefaultProps
+      );
+    } else {
+      Constructor.getDefaultProps = getDefaultProps;
+    }
+  },
+  propTypes: function(Constructor, propTypes) {
+    if ("production" !== "development") {
+      validateTypeDef(
+        Constructor,
+        propTypes,
+        ReactPropTypeLocations.prop
+      );
+    }
+    Constructor.propTypes = assign(
+      {},
+      Constructor.propTypes,
+      propTypes
+    );
+  },
+  statics: function(Constructor, statics) {
+    mixStaticSpecIntoComponent(Constructor, statics);
+  }
+};
+
+function validateTypeDef(Constructor, typeDef, location) {
+  for (var propName in typeDef) {
+    if (typeDef.hasOwnProperty(propName)) {
+      // use a warning instead of an invariant so components
+      // don't show up in prod but not in __DEV__
+      ("production" !== "development" ? warning(
+        typeof typeDef[propName] === 'function',
+        '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+        'React.PropTypes.',
+        Constructor.displayName || 'ReactClass',
+        ReactPropTypeLocationNames[location],
+        propName
+      ) : null);
+    }
+  }
+}
+
+function validateMethodOverride(proto, name) {
+  var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
+    ReactClassInterface[name] :
+    null;
+
+  // Disallow overriding of base class methods unless explicitly allowed.
+  if (ReactClassMixin.hasOwnProperty(name)) {
+    ("production" !== "development" ? invariant(
+      specPolicy === SpecPolicy.OVERRIDE_BASE,
+      'ReactClassInterface: You are attempting to override ' +
+      '`%s` from your class specification. Ensure that your method names ' +
+      'do not overlap with React methods.',
+      name
+    ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
+  }
+
+  // Disallow defining methods more than once unless explicitly allowed.
+  if (proto.hasOwnProperty(name)) {
+    ("production" !== "development" ? invariant(
+      specPolicy === SpecPolicy.DEFINE_MANY ||
+      specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
+      'ReactClassInterface: You are attempting to define ' +
+      '`%s` on your component more than once. This conflict may be due ' +
+      'to a mixin.',
+      name
+    ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
+    specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
+  }
+}
+
+/**
+ * Mixin helper which handles policy validation and reserved
+ * specification keys when building React classses.
+ */
+function mixSpecIntoComponent(Constructor, spec) {
+  if (!spec) {
+    return;
+  }
+
+  ("production" !== "development" ? invariant(
+    typeof spec !== 'function',
+    'ReactClass: You\'re attempting to ' +
+    'use a component class as a mixin. Instead, just use a regular object.'
+  ) : invariant(typeof spec !== 'function'));
+  ("production" !== "development" ? invariant(
+    !ReactElement.isValidElement(spec),
+    'ReactClass: You\'re attempting to ' +
+    'use a component as a mixin. Instead, just use a regular object.'
+  ) : invariant(!ReactElement.isValidElement(spec)));
+
+  var proto = Constructor.prototype;
+
+  // By handling mixins before any other properties, we ensure the same
+  // chaining order is applied to methods with DEFINE_MANY policy, whether
+  // mixins are listed before or after these methods in the spec.
+  if (spec.hasOwnProperty(MIXINS_KEY)) {
+    RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
+  }
+
+  for (var name in spec) {
+    if (!spec.hasOwnProperty(name)) {
+      continue;
+    }
+
+    if (name === MIXINS_KEY) {
+      // We have already handled mixins in a special case above
+      continue;
+    }
+
+    var property = spec[name];
+    validateMethodOverride(proto, name);
+
+    if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
+      RESERVED_SPEC_KEYS[name](Constructor, property);
+    } else {
+      // Setup methods on prototype:
+      // The following member methods should not be automatically bound:
+      // 1. Expected ReactClass methods (in the "interface").
+      // 2. Overridden methods (that were mixed in).
+      var isReactClassMethod =
+        ReactClassInterface.hasOwnProperty(name);
+      var isAlreadyDefined = proto.hasOwnProperty(name);
+      var markedDontBind = property && property.__reactDontBind;
+      var isFunction = typeof property === 'function';
+      var shouldAutoBind =
+        isFunction &&
+        !isReactClassMethod &&
+        !isAlreadyDefined &&
+        !markedDontBind;
+
+      if (shouldAutoBind) {
+        if (!proto.__reactAutoBindMap) {
+          proto.__reactAutoBindMap = {};
+        }
+        proto.__reactAutoBindMap[name] = property;
+        proto[name] = property;
+      } else {
+        if (isAlreadyDefined) {
+          var specPolicy = ReactClassInterface[name];
+
+          // These cases should already be caught by validateMethodOverride
+          ("production" !== "development" ? invariant(
+            isReactClassMethod && (
+              (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)
+            ),
+            'ReactClass: Unexpected spec policy %s for key %s ' +
+            'when mixing in component specs.',
+            specPolicy,
+            name
+          ) : invariant(isReactClassMethod && (
+            (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)
+          )));
+
+          // For methods which are defined more than once, call the existing
+          // methods before calling the new property, merging if appropriate.
+          if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
+            proto[name] = createMergedResultFunction(proto[name], property);
+          } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
+            proto[name] = createChainedFunction(proto[name], property);
+          }
+        } else {
+          proto[name] = property;
+          if ("production" !== "development") {
+            // Add verbose displayName to the function, which helps when looking
+            // at profiling tools.
+            if (typeof property === 'function' && spec.displayName) {
+              proto[name].displayName = spec.displayName + '_' + name;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+function mixStaticSpecIntoComponent(Constructor, statics) {
+  if (!statics) {
+    return;
+  }
+  for (var name in statics) {
+    var property = statics[name];
+    if (!statics.hasOwnProperty(name)) {
+      continue;
+    }
+
+    var isReserved = name in RESERVED_SPEC_KEYS;
+    ("production" !== "development" ? invariant(
+      !isReserved,
+      'ReactClass: You are attempting to define a reserved ' +
+      'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
+      'as an instance property instead; it will still be accessible on the ' +
+      'constructor.',
+      name
+    ) : invariant(!isReserved));
+
+    var isInherited = name in Constructor;
+    ("production" !== "development" ? invariant(
+      !isInherited,
+      'ReactClass: You are attempting to define ' +
+      '`%s` on your component more than once. This conflict may be ' +
+      'due to a mixin.',
+      name
+    ) : invariant(!isInherited));
+    Constructor[name] = property;
+  }
+}
+
+/**
+ * Merge two objects, but throw if both contain the same key.
+ *
+ * @param {object} one The first object, which is mutated.
+ * @param {object} two The second object
+ * @return {object} one after it has been mutated to contain everything in two.
+ */
+function mergeIntoWithNoDuplicateKeys(one, two) {
+  ("production" !== "development" ? invariant(
+    one && two && typeof one === 'object' && typeof two === 'object',
+    'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
+  ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
+
+  for (var key in two) {
+    if (two.hasOwnProperty(key)) {
+      ("production" !== "development" ? invariant(
+        one[key] === undefined,
+        'mergeIntoWithNoDuplicateKeys(): ' +
+        'Tried to merge two objects with the same key: `%s`. This conflict ' +
+        'may be due to a mixin; in particular, this may be caused by two ' +
+        'getInitialState() or getDefaultProps() methods returning objects ' +
+        'with clashing keys.',
+        key
+      ) : invariant(one[key] === undefined));
+      one[key] = two[key];
+    }
+  }
+  return one;
+}
+
+/**
+ * Creates a function that invokes two functions and merges their return values.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createMergedResultFunction(one, two) {
+  return function mergedResult() {
+    var a = one.apply(this, arguments);
+    var b = two.apply(this, arguments);
+    if (a == null) {
+      return b;
+    } else if (b == null) {
+      return a;
+    }
+    var c = {};
+    mergeIntoWithNoDuplicateKeys(c, a);
+    mergeIntoWithNoDuplicateKeys(c, b);
+    return c;
+  };
+}
+
+/**
+ * Creates a function that invokes two functions and ignores their return vales.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createChainedFunction(one, two) {
+  return function chainedFunction() {
+    one.apply(this, arguments);
+    two.apply(this, arguments);
+  };
+}
+
+/**
+ * Binds a method to the component.
+ *
+ * @param {object} component Component whose method is going to be bound.
+ * @param {function} method Method to be bound.
+ * @return {function} The bound method.
+ */
+function bindAutoBindMethod(component, method) {
+  var boundMethod = method.bind(component);
+  if ("production" !== "development") {
+    boundMethod.__reactBoundContext = component;
+    boundMethod.__reactBoundMethod = method;
+    boundMethod.__reactBoundArguments = null;
+    var componentName = component.constructor.displayName;
+    var _bind = boundMethod.bind;
+    /* eslint-disable block-scoped-var, no-undef */
+    boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+      // User is trying to bind() an autobound method; we effectively will
+      // ignore the value of "this" that the user is trying to use, so
+      // let's warn.
+      if (newThis !== component && newThis !== null) {
+        ("production" !== "development" ? warning(
+          false,
+          'bind(): React component methods may only be bound to the ' +
+          'component instance. See %s',
+          componentName
+        ) : null);
+      } else if (!args.length) {
+        ("production" !== "development" ? warning(
+          false,
+          'bind(): You are binding a component method to the component. ' +
+          'React does this for you automatically in a high-performance ' +
+          'way, so you can safely remove this call. See %s',
+          componentName
+        ) : null);
+        return boundMethod;
+      }
+      var reboundMethod = _bind.apply(boundMethod, arguments);
+      reboundMethod.__reactBoundContext = component;
+      reboundMethod.__reactBoundMethod = method;
+      reboundMethod.__reactBoundArguments = args;
+      return reboundMethod;
+      /* eslint-enable */
+    };
+  }
+  return boundMethod;
+}
+
+/**
+ * Binds all auto-bound methods in a component.
+ *
+ * @param {object} component Component whose method is going to be bound.
+ */
+function bindAutoBindMethods(component) {
+  for (var autoBindKey in component.__reactAutoBindMap) {
+    if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
+      var method = component.__reactAutoBindMap[autoBindKey];
+      component[autoBindKey] = bindAutoBindMethod(
+        component,
+        ReactErrorUtils.guard(
+          method,
+          component.constructor.displayName + '.' + autoBindKey
+        )
+      );
+    }
+  }
+}
+
+var typeDeprecationDescriptor = {
+  enumerable: false,
+  get: function() {
+    var displayName = this.displayName || this.name || 'Component';
+    ("production" !== "development" ? warning(
+      false,
+      '%s.type is deprecated. Use %s directly to access the class.',
+      displayName,
+      displayName
+    ) : null);
+    Object.defineProperty(this, 'type', {
+      value: this
+    });
+    return this;
+  }
+};
+
+/**
+ * Add more to the ReactClass base class. These are all legacy features and
+ * therefore not already part of the modern ReactComponent.
+ */
+var ReactClassMixin = {
+
+  /**
+   * TODO: This will be deprecated because state should always keep a consistent
+   * type signature and the only use case for this, is to avoid that.
+   */
+  replaceState: function(newState, callback) {
+    ReactUpdateQueue.enqueueReplaceState(this, newState);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  },
+
+  /**
+   * Checks whether or not this composite component is mounted.
+   * @return {boolean} True if mounted, false otherwise.
+   * @protected
+   * @final
+   */
+  isMounted: function() {
+    if ("production" !== "development") {
+      var owner = ReactCurrentOwner.current;
+      if (owner !== null) {
+        ("production" !== "development" ? warning(
+          owner._warnedAboutRefsInRender,
+          '%s is accessing isMounted inside its render() function. ' +
+          'render() should be a pure function of props and state. It should ' +
+          'never access something that requires stale data from the previous ' +
+          'render, such as refs. Move this logic to componentDidMount and ' +
+          'componentDidUpdate instead.',
+          owner.getName() || 'A component'
+        ) : null);
+        owner._warnedAboutRefsInRender = true;
+      }
+    }
+    var internalInstance = ReactInstanceMap.get(this);
+    return (
+      internalInstance &&
+      internalInstance !== ReactLifeCycle.currentlyMountingInstance
+    );
+  },
+
+  /**
+   * Sets a subset of the props.
+   *
+   * @param {object} partialProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @public
+   * @deprecated
+   */
+  setProps: function(partialProps, callback) {
+    ReactUpdateQueue.enqueueSetProps(this, partialProps);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  },
+
+  /**
+   * Replace all the props.
+   *
+   * @param {object} newProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @public
+   * @deprecated
+   */
+  replaceProps: function(newProps, callback) {
+    ReactUpdateQueue.enqueueReplaceProps(this, newProps);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  }
+};
+
+var ReactClassComponent = function() {};
+assign(
+  ReactClassComponent.prototype,
+  ReactComponent.prototype,
+  ReactClassMixin
+);
+
+/**
+ * Module for creating composite components.
+ *
+ * @class ReactClass
+ */
+var ReactClass = {
+
+  /**
+   * Creates a composite component class given a class specification.
+   *
+   * @param {object} spec Class specification (which must define `render`).
+   * @return {function} Component constructor function.
+   * @public
+   */
+  createClass: function(spec) {
+    var Constructor = function(props, context) {
+      // This constructor is overridden by mocks. The argument is used
+      // by mocks to assert on what gets mounted.
+
+      if ("production" !== "development") {
+        ("production" !== "development" ? warning(
+          this instanceof Constructor,
+          'Something is calling a React component directly. Use a factory or ' +
+          'JSX instead. See: http://fb.me/react-legacyfactory'
+        ) : null);
+      }
+
+      // Wire up auto-binding
+      if (this.__reactAutoBindMap) {
+        bindAutoBindMethods(this);
+      }
+
+      this.props = props;
+      this.context = context;
+      this.state = null;
+
+      // ReactClasses doesn't have constructors. Instead, they use the
+      // getInitialState and componentWillMount methods for initialization.
+
+      var initialState = this.getInitialState ? this.getInitialState() : null;
+      if ("production" !== "development") {
+        // We allow auto-mocks to proceed as if they're returning null.
+        if (typeof initialState === 'undefined' &&
+            this.getInitialState._isMockFunction) {
+          // This is probably bad practice. Consider warning here and
+          // deprecating this convenience.
+          initialState = null;
+        }
+      }
+      ("production" !== "development" ? invariant(
+        typeof initialState === 'object' && !Array.isArray(initialState),
+        '%s.getInitialState(): must return an object or null',
+        Constructor.displayName || 'ReactCompositeComponent'
+      ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
+
+      this.state = initialState;
+    };
+    Constructor.prototype = new ReactClassComponent();
+    Constructor.prototype.constructor = Constructor;
+
+    injectedMixins.forEach(
+      mixSpecIntoComponent.bind(null, Constructor)
+    );
+
+    mixSpecIntoComponent(Constructor, spec);
+
+    // Initialize the defaultProps property after all mixins have been merged
+    if (Constructor.getDefaultProps) {
+      Constructor.defaultProps = Constructor.getDefaultProps();
+    }
+
+    if ("production" !== "development") {
+      // This is a tag to indicate that the use of these method names is ok,
+      // since it's used with createClass. If it's not, then it's likely a
+      // mistake so we'll warn you to use the static property, property
+      // initializer or constructor respectively.
+      if (Constructor.getDefaultProps) {
+        Constructor.getDefaultProps.isReactClassApproved = {};
+      }
+      if (Constructor.prototype.getInitialState) {
+        Constructor.prototype.getInitialState.isReactClassApproved = {};
+      }
+    }
+
+    ("production" !== "development" ? invariant(
+      Constructor.prototype.render,
+      'createClass(...): Class specification must implement a `render` method.'
+    ) : invariant(Constructor.prototype.render));
+
+    if ("production" !== "development") {
+      ("production" !== "development" ? warning(
+        !Constructor.prototype.componentShouldUpdate,
+        '%s has a method called ' +
+        'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
+        'The name is phrased as a question because the function is ' +
+        'expected to return a value.',
+        spec.displayName || 'A component'
+      ) : null);
+    }
+
+    // Reduce time spent doing lookups by setting these on the prototype.
+    for (var methodName in ReactClassInterface) {
+      if (!Constructor.prototype[methodName]) {
+        Constructor.prototype[methodName] = null;
+      }
+    }
+
+    // Legacy hook
+    Constructor.type = Constructor;
+    if ("production" !== "development") {
+      try {
+        Object.defineProperty(Constructor, 'type', typeDeprecationDescriptor);
+      } catch (x) {
+        // IE will fail on defineProperty (es5-shim/sham too)
+      }
+    }
+
+    return Constructor;
+  },
+
+  injection: {
+    injectMixin: function(mixin) {
+      injectedMixins.push(mixin);
+    }
+  }
+
+};
+
+module.exports = ReactClass;
+
+},{"135":135,"140":140,"141":141,"154":154,"27":27,"34":34,"39":39,"57":57,"60":60,"67":67,"68":68,"76":76,"77":77,"86":86}],34:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponent
+ */
+
+'use strict';
+
+var ReactUpdateQueue = _dereq_(86);
+
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+/**
+ * Base class helpers for the updating state of a component.
+ */
+function ReactComponent(props, context) {
+  this.props = props;
+  this.context = context;
+}
+
+/**
+ * Sets a subset of the state. Always use this to mutate
+ * state. You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * There is no guarantee that calls to `setState` will run synchronously,
+ * as they may eventually be batched together.  You can provide an optional
+ * callback that will be executed when the call to setState is actually
+ * completed.
+ *
+ * When a function is provided to setState, it will be called at some point in
+ * the future (not synchronously). It will be called with the up to date
+ * component arguments (state, props, context). These values can be different
+ * from this.* because your function may be called after receiveProps but before
+ * shouldComponentUpdate, and this new state, props, and context will not yet be
+ * assigned to this.
+ *
+ * @param {object|function} partialState Next partial state or function to
+ *        produce next partial state to be merged with current state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ReactComponent.prototype.setState = function(partialState, callback) {
+  ("production" !== "development" ? invariant(
+    typeof partialState === 'object' ||
+    typeof partialState === 'function' ||
+    partialState == null,
+    'setState(...): takes an object of state variables to update or a ' +
+    'function which returns an object of state variables.'
+  ) : invariant(typeof partialState === 'object' ||
+  typeof partialState === 'function' ||
+  partialState == null));
+  if ("production" !== "development") {
+    ("production" !== "development" ? warning(
+      partialState != null,
+      'setState(...): You passed an undefined or null state object; ' +
+      'instead, use forceUpdate().'
+    ) : null);
+  }
+  ReactUpdateQueue.enqueueSetState(this, partialState);
+  if (callback) {
+    ReactUpdateQueue.enqueueCallback(this, callback);
+  }
+};
+
+/**
+ * Forces an update. This should only be invoked when it is known with
+ * certainty that we are **not** in a DOM transaction.
+ *
+ * You may want to call this when you know that some deeper aspect of the
+ * component's state has changed but `setState` was not called.
+ *
+ * This will not invoke `shouldComponentUpdate`, but it will invoke
+ * `componentWillUpdate` and `componentDidUpdate`.
+ *
+ * @param {?function} callback Called after update is complete.
+ * @final
+ * @protected
+ */
+ReactComponent.prototype.forceUpdate = function(callback) {
+  ReactUpdateQueue.enqueueForceUpdate(this);
+  if (callback) {
+    ReactUpdateQueue.enqueueCallback(this, callback);
+  }
+};
+
+/**
+ * Deprecated APIs. These APIs used to exist on classic React classes but since
+ * we would like to deprecate them, we're not going to move them over to this
+ * modern base class. Instead, we define a getter that warns if it's accessed.
+ */
+if ("production" !== "development") {
+  var deprecatedAPIs = {
+    getDOMNode: 'getDOMNode',
+    isMounted: 'isMounted',
+    replaceProps: 'replaceProps',
+    replaceState: 'replaceState',
+    setProps: 'setProps'
+  };
+  var defineDeprecationWarning = function(methodName, displayName) {
+    try {
+      Object.defineProperty(ReactComponent.prototype, methodName, {
+        get: function() {
+          ("production" !== "development" ? warning(
+            false,
+            '%s(...) is deprecated in plain JavaScript React classes.',
+            displayName
+          ) : null);
+          return undefined;
+        }
+      });
+    } catch (x) {
+      // IE will fail on defineProperty (es5-shim/sham too)
+    }
+  };
+  for (var fnName in deprecatedAPIs) {
+    if (deprecatedAPIs.hasOwnProperty(fnName)) {
+      defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
+    }
+  }
+}
+
+module.exports = ReactComponent;
+
+},{"135":135,"154":154,"86":86}],35:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentBrowserEnvironment
+ */
+
+/*jslint evil: true */
+
+'use strict';
+
+var ReactDOMIDOperations = _dereq_(44);
+var ReactMount = _dereq_(70);
+
+/**
+ * Abstracts away all functionality of the reconciler that requires knowledge of
+ * the browser context. TODO: These callers should be refactored to avoid the
+ * need for this injection.
+ */
+var ReactComponentBrowserEnvironment = {
+
+  processChildrenUpdates:
+    ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
+
+  replaceNodeWithMarkupByID:
+    ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
+
+  /**
+   * If a particular environment requires that some resources be cleaned up,
+   * specify this in the injected Mixin. In the DOM, we would likely want to
+   * purge any cached node ID lookups.
+   *
+   * @private
+   */
+  unmountIDFromEnvironment: function(rootNodeID) {
+    ReactMount.purgeID(rootNodeID);
+  }
+
+};
+
+module.exports = ReactComponentBrowserEnvironment;
+
+},{"44":44,"70":70}],36:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentEnvironment
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+var injected = false;
+
+var ReactComponentEnvironment = {
+
+  /**
+   * Optionally injectable environment dependent cleanup hook. (server vs.
+   * browser etc). Example: A browser system caches DOM nodes based on component
+   * ID and must remove that cache entry when this instance is unmounted.
+   */
+  unmountIDFromEnvironment: null,
+
+  /**
+   * Optionally injectable hook for swapping out mount images in the middle of
+   * the tree.
+   */
+  replaceNodeWithMarkupByID: null,
+
+  /**
+   * Optionally injectable hook for processing a queue of child updates. Will
+   * later move into MultiChildComponents.
+   */
+  processChildrenUpdates: null,
+
+  injection: {
+    injectEnvironment: function(environment) {
+      ("production" !== "development" ? invariant(
+        !injected,
+        'ReactCompositeComponent: injectEnvironment() can only be called once.'
+      ) : invariant(!injected));
+      ReactComponentEnvironment.unmountIDFromEnvironment =
+        environment.unmountIDFromEnvironment;
+      ReactComponentEnvironment.replaceNodeWithMarkupByID =
+        environment.replaceNodeWithMarkupByID;
+      ReactComponentEnvironment.processChildrenUpdates =
+        environment.processChildrenUpdates;
+      injected = true;
+    }
+  }
+
+};
+
+module.exports = ReactComponentEnvironment;
+
+},{"135":135}],37:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCompositeComponent
+ */
+
+'use strict';
+
+var ReactComponentEnvironment = _dereq_(36);
+var ReactContext = _dereq_(38);
+var ReactCurrentOwner = _dereq_(39);
+var ReactElement = _dereq_(57);
+var ReactElementValidator = _dereq_(58);
+var ReactInstanceMap = _dereq_(67);
+var ReactLifeCycle = _dereq_(68);
+var ReactNativeComponent = _dereq_(73);
+var ReactPerf = _dereq_(75);
+var ReactPropTypeLocations = _dereq_(77);
+var ReactPropTypeLocationNames = _dereq_(76);
+var ReactReconciler = _dereq_(81);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+var emptyObject = _dereq_(115);
+var invariant = _dereq_(135);
+var shouldUpdateReactComponent = _dereq_(151);
+var warning = _dereq_(154);
+
+function getDeclarationErrorAddendum(component) {
+  var owner = component._currentElement._owner || null;
+  if (owner) {
+    var name = owner.getName();
+    if (name) {
+      return ' Check the render method of `' + name + '`.';
+    }
+  }
+  return '';
+}
+
+/**
+ * ------------------ The Life-Cycle of a Composite Component ------------------
+ *
+ * - constructor: Initialization of state. The instance is now retained.
+ *   - componentWillMount
+ *   - render
+ *   - [children's constructors]
+ *     - [children's componentWillMount and render]
+ *     - [children's componentDidMount]
+ *     - componentDidMount
+ *
+ *       Update Phases:
+ *       - componentWillReceiveProps (only called if parent updated)
+ *       - shouldComponentUpdate
+ *         - componentWillUpdate
+ *           - render
+ *           - [children's constructors or receive props phases]
+ *         - componentDidUpdate
+ *
+ *     - componentWillUnmount
+ *     - [children's componentWillUnmount]
+ *   - [children destroyed]
+ * - (destroyed): The instance is now blank, released by React and ready for GC.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+/**
+ * An incrementing ID assigned to each component when it is mounted. This is
+ * used to enforce the order in which `ReactUpdates` updates dirty components.
+ *
+ * @private
+ */
+var nextMountID = 1;
+
+/**
+ * @lends {ReactCompositeComponent.prototype}
+ */
+var ReactCompositeComponentMixin = {
+
+  /**
+   * Base constructor for all composite component.
+   *
+   * @param {ReactElement} element
+   * @final
+   * @internal
+   */
+  construct: function(element) {
+    this._currentElement = element;
+    this._rootNodeID = null;
+    this._instance = null;
+
+    // See ReactUpdateQueue
+    this._pendingElement = null;
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+
+    this._renderedComponent = null;
+
+    this._context = null;
+    this._mountOrder = 0;
+    this._isTopLevel = false;
+
+    // See ReactUpdates and ReactUpdateQueue.
+    this._pendingCallbacks = null;
+  },
+
+  /**
+   * Initializes the component, renders markup, and registers event listeners.
+   *
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {?string} Rendered markup to be inserted into the DOM.
+   * @final
+   * @internal
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._context = context;
+    this._mountOrder = nextMountID++;
+    this._rootNodeID = rootID;
+
+    var publicProps = this._processProps(this._currentElement.props);
+    var publicContext = this._processContext(this._currentElement._context);
+
+    var Component = ReactNativeComponent.getComponentClassForElement(
+      this._currentElement
+    );
+
+    // Initialize the public class
+    var inst = new Component(publicProps, publicContext);
+
+    if ("production" !== "development") {
+      // This will throw later in _renderValidatedComponent, but add an early
+      // warning now to help debugging
+      ("production" !== "development" ? warning(
+        inst.render != null,
+        '%s(...): No `render` method found on the returned component ' +
+        'instance: you may have forgotten to define `render` in your ' +
+        'component or you may have accidentally tried to render an element ' +
+        'whose type is a function that isn\'t a React component.',
+        Component.displayName || Component.name || 'Component'
+      ) : null);
+    }
+
+    // These should be set up in the constructor, but as a convenience for
+    // simpler class abstractions, we set them up after the fact.
+    inst.props = publicProps;
+    inst.context = publicContext;
+    inst.refs = emptyObject;
+
+    this._instance = inst;
+
+    // Store a reference from the instance back to the internal representation
+    ReactInstanceMap.set(inst, this);
+
+    if ("production" !== "development") {
+      this._warnIfContextsDiffer(this._currentElement._context, context);
+    }
+
+    if ("production" !== "development") {
+      // Since plain JS classes are defined without any special initialization
+      // logic, we can not catch common errors early. Therefore, we have to
+      // catch them here, at initialization time, instead.
+      ("production" !== "development" ? warning(
+        !inst.getInitialState ||
+        inst.getInitialState.isReactClassApproved,
+        'getInitialState was defined on %s, a plain JavaScript class. ' +
+        'This is only supported for classes created using React.createClass. ' +
+        'Did you mean to define a state property instead?',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== "development" ? warning(
+        !inst.propTypes,
+        'propTypes was defined as an instance property on %s. Use a static ' +
+        'property to define propTypes instead.',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== "development" ? warning(
+        !inst.contextTypes,
+        'contextTypes was defined as an instance property on %s. Use a ' +
+        'static property to define contextTypes instead.',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== "development" ? warning(
+        typeof inst.componentShouldUpdate !== 'function',
+        '%s has a method called ' +
+        'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
+        'The name is phrased as a question because the function is ' +
+        'expected to return a value.',
+        (this.getName() || 'A component')
+      ) : null);
+    }
+
+    var initialState = inst.state;
+    if (initialState === undefined) {
+      inst.state = initialState = null;
+    }
+    ("production" !== "development" ? invariant(
+      typeof initialState === 'object' && !Array.isArray(initialState),
+      '%s.state: must be set to an object or null',
+      this.getName() || 'ReactCompositeComponent'
+    ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
+
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+
+    var renderedElement;
+
+    var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
+    ReactLifeCycle.currentlyMountingInstance = this;
+    try {
+      if (inst.componentWillMount) {
+        inst.componentWillMount();
+        // When mounting, calls to `setState` by `componentWillMount` will set
+        // `this._pendingStateQueue` without triggering a re-render.
+        if (this._pendingStateQueue) {
+          inst.state = this._processPendingState(inst.props, inst.context);
+        }
+      }
+
+      renderedElement = this._renderValidatedComponent();
+    } finally {
+      ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
+    }
+
+    this._renderedComponent = this._instantiateReactComponent(
+      renderedElement,
+      this._currentElement.type // The wrapping type
+    );
+
+    var markup = ReactReconciler.mountComponent(
+      this._renderedComponent,
+      rootID,
+      transaction,
+      this._processChildContext(context)
+    );
+    if (inst.componentDidMount) {
+      transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
+    }
+
+    return markup;
+  },
+
+  /**
+   * Releases any resources allocated by `mountComponent`.
+   *
+   * @final
+   * @internal
+   */
+  unmountComponent: function() {
+    var inst = this._instance;
+
+    if (inst.componentWillUnmount) {
+      var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance;
+      ReactLifeCycle.currentlyUnmountingInstance = this;
+      try {
+        inst.componentWillUnmount();
+      } finally {
+        ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting;
+      }
+    }
+
+    ReactReconciler.unmountComponent(this._renderedComponent);
+    this._renderedComponent = null;
+
+    // Reset pending fields
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+    this._pendingCallbacks = null;
+    this._pendingElement = null;
+
+    // These fields do not really need to be reset since this object is no
+    // longer accessible.
+    this._context = null;
+    this._rootNodeID = null;
+
+    // Delete the reference from the instance to this internal representation
+    // which allow the internals to be properly cleaned up even if the user
+    // leaks a reference to the public instance.
+    ReactInstanceMap.remove(inst);
+
+    // Some existing components rely on inst.props even after they've been
+    // destroyed (in event handlers).
+    // TODO: inst.props = null;
+    // TODO: inst.state = null;
+    // TODO: inst.context = null;
+  },
+
+  /**
+   * Schedule a partial update to the props. Only used for internal testing.
+   *
+   * @param {object} partialProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @internal
+   */
+  _setPropsInternal: function(partialProps, callback) {
+    // This is a deoptimized path. We optimize for always having an element.
+    // This creates an extra internal element.
+    var element = this._pendingElement || this._currentElement;
+    this._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      assign({}, element.props, partialProps)
+    );
+    ReactUpdates.enqueueUpdate(this, callback);
+  },
+
+  /**
+   * Filters the context object to only contain keys specified in
+   * `contextTypes`
+   *
+   * @param {object} context
+   * @return {?object}
+   * @private
+   */
+  _maskContext: function(context) {
+    var maskedContext = null;
+    // This really should be getting the component class for the element,
+    // but we know that we're not going to need it for built-ins.
+    if (typeof this._currentElement.type === 'string') {
+      return emptyObject;
+    }
+    var contextTypes = this._currentElement.type.contextTypes;
+    if (!contextTypes) {
+      return emptyObject;
+    }
+    maskedContext = {};
+    for (var contextName in contextTypes) {
+      maskedContext[contextName] = context[contextName];
+    }
+    return maskedContext;
+  },
+
+  /**
+   * Filters the context object to only contain keys specified in
+   * `contextTypes`, and asserts that they are valid.
+   *
+   * @param {object} context
+   * @return {?object}
+   * @private
+   */
+  _processContext: function(context) {
+    var maskedContext = this._maskContext(context);
+    if ("production" !== "development") {
+      var Component = ReactNativeComponent.getComponentClassForElement(
+        this._currentElement
+      );
+      if (Component.contextTypes) {
+        this._checkPropTypes(
+          Component.contextTypes,
+          maskedContext,
+          ReactPropTypeLocations.context
+        );
+      }
+    }
+    return maskedContext;
+  },
+
+  /**
+   * @param {object} currentContext
+   * @return {object}
+   * @private
+   */
+  _processChildContext: function(currentContext) {
+    var inst = this._instance;
+    var childContext = inst.getChildContext && inst.getChildContext();
+    if (childContext) {
+      ("production" !== "development" ? invariant(
+        typeof inst.constructor.childContextTypes === 'object',
+        '%s.getChildContext(): childContextTypes must be defined in order to ' +
+        'use getChildContext().',
+        this.getName() || 'ReactCompositeComponent'
+      ) : invariant(typeof inst.constructor.childContextTypes === 'object'));
+      if ("production" !== "development") {
+        this._checkPropTypes(
+          inst.constructor.childContextTypes,
+          childContext,
+          ReactPropTypeLocations.childContext
+        );
+      }
+      for (var name in childContext) {
+        ("production" !== "development" ? invariant(
+          name in inst.constructor.childContextTypes,
+          '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
+          this.getName() || 'ReactCompositeComponent',
+          name
+        ) : invariant(name in inst.constructor.childContextTypes));
+      }
+      return assign({}, currentContext, childContext);
+    }
+    return currentContext;
+  },
+
+  /**
+   * Processes props by setting default values for unspecified props and
+   * asserting that the props are valid. Does not mutate its argument; returns
+   * a new props object with defaults merged in.
+   *
+   * @param {object} newProps
+   * @return {object}
+   * @private
+   */
+  _processProps: function(newProps) {
+    if ("production" !== "development") {
+      var Component = ReactNativeComponent.getComponentClassForElement(
+        this._currentElement
+      );
+      if (Component.propTypes) {
+        this._checkPropTypes(
+          Component.propTypes,
+          newProps,
+          ReactPropTypeLocations.prop
+        );
+      }
+    }
+    return newProps;
+  },
+
+  /**
+   * Assert that the props are valid
+   *
+   * @param {object} propTypes Map of prop name to a ReactPropType
+   * @param {object} props
+   * @param {string} location e.g. "prop", "context", "child context"
+   * @private
+   */
+  _checkPropTypes: function(propTypes, props, location) {
+    // TODO: Stop validating prop types here and only use the element
+    // validation.
+    var componentName = this.getName();
+    for (var propName in propTypes) {
+      if (propTypes.hasOwnProperty(propName)) {
+        var error;
+        try {
+          // This is intentionally an invariant that gets caught. It's the same
+          // behavior as without this statement except with a better message.
+          ("production" !== "development" ? invariant(
+            typeof propTypes[propName] === 'function',
+            '%s: %s type `%s` is invalid; it must be a function, usually ' +
+            'from React.PropTypes.',
+            componentName || 'React class',
+            ReactPropTypeLocationNames[location],
+            propName
+          ) : invariant(typeof propTypes[propName] === 'function'));
+          error = propTypes[propName](props, propName, componentName, location);
+        } catch (ex) {
+          error = ex;
+        }
+        if (error instanceof Error) {
+          // We may want to extend this logic for similar errors in
+          // React.render calls, so I'm abstracting it away into
+          // a function to minimize refactoring in the future
+          var addendum = getDeclarationErrorAddendum(this);
+
+          if (location === ReactPropTypeLocations.prop) {
+            // Preface gives us something to blacklist in warning module
+            ("production" !== "development" ? warning(
+              false,
+              'Failed Composite propType: %s%s',
+              error.message,
+              addendum
+            ) : null);
+          } else {
+            ("production" !== "development" ? warning(
+              false,
+              'Failed Context Types: %s%s',
+              error.message,
+              addendum
+            ) : null);
+          }
+        }
+      }
+    }
+  },
+
+  receiveComponent: function(nextElement, transaction, nextContext) {
+    var prevElement = this._currentElement;
+    var prevContext = this._context;
+
+    this._pendingElement = null;
+
+    this.updateComponent(
+      transaction,
+      prevElement,
+      nextElement,
+      prevContext,
+      nextContext
+    );
+  },
+
+  /**
+   * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate`
+   * is set, update the component.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  performUpdateIfNecessary: function(transaction) {
+    if (this._pendingElement != null) {
+      ReactReconciler.receiveComponent(
+        this,
+        this._pendingElement || this._currentElement,
+        transaction,
+        this._context
+      );
+    }
+
+    if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
+      if ("production" !== "development") {
+        ReactElementValidator.checkAndWarnForMutatedProps(
+          this._currentElement
+        );
+      }
+
+      this.updateComponent(
+        transaction,
+        this._currentElement,
+        this._currentElement,
+        this._context,
+        this._context
+      );
+    }
+  },
+
+  /**
+   * Compare two contexts, warning if they are different
+   * TODO: Remove this check when owner-context is removed
+   */
+   _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) {
+    ownerBasedContext = this._maskContext(ownerBasedContext);
+    parentBasedContext = this._maskContext(parentBasedContext);
+    var parentKeys = Object.keys(parentBasedContext).sort();
+    var displayName = this.getName() || 'ReactCompositeComponent';
+    for (var i = 0; i < parentKeys.length; i++) {
+      var key = parentKeys[i];
+      ("production" !== "development" ? warning(
+        ownerBasedContext[key] === parentBasedContext[key],
+        'owner-based and parent-based contexts differ '  +
+        '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
+        '(see: http://fb.me/react-context-by-parent)',
+        ownerBasedContext[key],
+        parentBasedContext[key],
+        key,
+        displayName
+      ) : null);
+    }
+  },
+
+  /**
+   * Perform an update to a mounted component. The componentWillReceiveProps and
+   * shouldComponentUpdate methods are called, then (assuming the update isn't
+   * skipped) the remaining update lifecycle methods are called and the DOM
+   * representation is updated.
+   *
+   * By default, this implements React's rendering and reconciliation algorithm.
+   * Sophisticated clients may wish to override this.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @param {ReactElement} prevParentElement
+   * @param {ReactElement} nextParentElement
+   * @internal
+   * @overridable
+   */
+  updateComponent: function(
+    transaction,
+    prevParentElement,
+    nextParentElement,
+    prevUnmaskedContext,
+    nextUnmaskedContext
+  ) {
+    var inst = this._instance;
+
+    var nextContext = inst.context;
+    var nextProps = inst.props;
+
+    // Distinguish between a props update versus a simple state update
+    if (prevParentElement !== nextParentElement) {
+      nextContext = this._processContext(nextParentElement._context);
+      nextProps = this._processProps(nextParentElement.props);
+
+      if ("production" !== "development") {
+        if (nextUnmaskedContext != null) {
+          this._warnIfContextsDiffer(
+            nextParentElement._context,
+            nextUnmaskedContext
+          );
+        }
+      }
+
+      // An update here will schedule an update but immediately set
+      // _pendingStateQueue which will ensure that any state updates gets
+      // immediately reconciled instead of waiting for the next batch.
+
+      if (inst.componentWillReceiveProps) {
+        inst.componentWillReceiveProps(nextProps, nextContext);
+      }
+    }
+
+    var nextState = this._processPendingState(nextProps, nextContext);
+
+    var shouldUpdate =
+      this._pendingForceUpdate ||
+      !inst.shouldComponentUpdate ||
+      inst.shouldComponentUpdate(nextProps, nextState, nextContext);
+
+    if ("production" !== "development") {
+      ("production" !== "development" ? warning(
+        typeof shouldUpdate !== 'undefined',
+        '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
+        'boolean value. Make sure to return true or false.',
+        this.getName() || 'ReactCompositeComponent'
+      ) : null);
+    }
+
+    if (shouldUpdate) {
+      this._pendingForceUpdate = false;
+      // Will set `this.props`, `this.state` and `this.context`.
+      this._performComponentUpdate(
+        nextParentElement,
+        nextProps,
+        nextState,
+        nextContext,
+        transaction,
+        nextUnmaskedContext
+      );
+    } else {
+      // If it's determined that a component should not update, we still want
+      // to set props and state but we shortcut the rest of the update.
+      this._currentElement = nextParentElement;
+      this._context = nextUnmaskedContext;
+      inst.props = nextProps;
+      inst.state = nextState;
+      inst.context = nextContext;
+    }
+  },
+
+  _processPendingState: function(props, context) {
+    var inst = this._instance;
+    var queue = this._pendingStateQueue;
+    var replace = this._pendingReplaceState;
+    this._pendingReplaceState = false;
+    this._pendingStateQueue = null;
+
+    if (!queue) {
+      return inst.state;
+    }
+
+    var nextState = assign({}, replace ? queue[0] : inst.state);
+    for (var i = replace ? 1 : 0; i < queue.length; i++) {
+      var partial = queue[i];
+      assign(
+        nextState,
+        typeof partial === 'function' ?
+          partial.call(inst, nextState, props, context) :
+          partial
+      );
+    }
+
+    return nextState;
+  },
+
+  /**
+   * Merges new props and state, notifies delegate methods of update and
+   * performs update.
+   *
+   * @param {ReactElement} nextElement Next element
+   * @param {object} nextProps Next public object to set as properties.
+   * @param {?object} nextState Next object to set as state.
+   * @param {?object} nextContext Next public object to set as context.
+   * @param {ReactReconcileTransaction} transaction
+   * @param {?object} unmaskedContext
+   * @private
+   */
+  _performComponentUpdate: function(
+    nextElement,
+    nextProps,
+    nextState,
+    nextContext,
+    transaction,
+    unmaskedContext
+  ) {
+    var inst = this._instance;
+
+    var prevProps = inst.props;
+    var prevState = inst.state;
+    var prevContext = inst.context;
+
+    if (inst.componentWillUpdate) {
+      inst.componentWillUpdate(nextProps, nextState, nextContext);
+    }
+
+    this._currentElement = nextElement;
+    this._context = unmaskedContext;
+    inst.props = nextProps;
+    inst.state = nextState;
+    inst.context = nextContext;
+
+    this._updateRenderedComponent(transaction, unmaskedContext);
+
+    if (inst.componentDidUpdate) {
+      transaction.getReactMountReady().enqueue(
+        inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext),
+        inst
+      );
+    }
+  },
+
+  /**
+   * Call the component's `render` method and update the DOM accordingly.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  _updateRenderedComponent: function(transaction, context) {
+    var prevComponentInstance = this._renderedComponent;
+    var prevRenderedElement = prevComponentInstance._currentElement;
+    var nextRenderedElement = this._renderValidatedComponent();
+    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
+      ReactReconciler.receiveComponent(
+        prevComponentInstance,
+        nextRenderedElement,
+        transaction,
+        this._processChildContext(context)
+      );
+    } else {
+      // These two IDs are actually the same! But nothing should rely on that.
+      var thisID = this._rootNodeID;
+      var prevComponentID = prevComponentInstance._rootNodeID;
+      ReactReconciler.unmountComponent(prevComponentInstance);
+
+      this._renderedComponent = this._instantiateReactComponent(
+        nextRenderedElement,
+        this._currentElement.type
+      );
+      var nextMarkup = ReactReconciler.mountComponent(
+        this._renderedComponent,
+        thisID,
+        transaction,
+        context
+      );
+      this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
+    }
+  },
+
+  /**
+   * @protected
+   */
+  _replaceNodeWithMarkupByID: function(prevComponentID, nextMarkup) {
+    ReactComponentEnvironment.replaceNodeWithMarkupByID(
+      prevComponentID,
+      nextMarkup
+    );
+  },
+
+  /**
+   * @protected
+   */
+  _renderValidatedComponentWithoutOwnerOrContext: function() {
+    var inst = this._instance;
+    var renderedComponent = inst.render();
+    if ("production" !== "development") {
+      // We allow auto-mocks to proceed as if they're returning null.
+      if (typeof renderedComponent === 'undefined' &&
+          inst.render._isMockFunction) {
+        // This is probably bad practice. Consider warning here and
+        // deprecating this convenience.
+        renderedComponent = null;
+      }
+    }
+
+    return renderedComponent;
+  },
+
+  /**
+   * @private
+   */
+  _renderValidatedComponent: function() {
+    var renderedComponent;
+    var previousContext = ReactContext.current;
+    ReactContext.current = this._processChildContext(
+      this._currentElement._context
+    );
+    ReactCurrentOwner.current = this;
+    try {
+      renderedComponent =
+        this._renderValidatedComponentWithoutOwnerOrContext();
+    } finally {
+      ReactContext.current = previousContext;
+      ReactCurrentOwner.current = null;
+    }
+    ("production" !== "development" ? invariant(
+      // TODO: An `isValidNode` function would probably be more appropriate
+      renderedComponent === null || renderedComponent === false ||
+      ReactElement.isValidElement(renderedComponent),
+      '%s.render(): A valid ReactComponent must be returned. You may have ' +
+        'returned undefined, an array or some other invalid object.',
+      this.getName() || 'ReactCompositeComponent'
+    ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate
+    renderedComponent === null || renderedComponent === false ||
+    ReactElement.isValidElement(renderedComponent)));
+    return renderedComponent;
+  },
+
+  /**
+   * Lazily allocates the refs object and stores `component` as `ref`.
+   *
+   * @param {string} ref Reference name.
+   * @param {component} component Component to store as `ref`.
+   * @final
+   * @private
+   */
+  attachRef: function(ref, component) {
+    var inst = this.getPublicInstance();
+    var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs;
+    refs[ref] = component.getPublicInstance();
+  },
+
+  /**
+   * Detaches a reference name.
+   *
+   * @param {string} ref Name to dereference.
+   * @final
+   * @private
+   */
+  detachRef: function(ref) {
+    var refs = this.getPublicInstance().refs;
+    delete refs[ref];
+  },
+
+  /**
+   * Get a text description of the component that can be used to identify it
+   * in error messages.
+   * @return {string} The name or null.
+   * @internal
+   */
+  getName: function() {
+    var type = this._currentElement.type;
+    var constructor = this._instance && this._instance.constructor;
+    return (
+      type.displayName || (constructor && constructor.displayName) ||
+      type.name || (constructor && constructor.name) ||
+      null
+    );
+  },
+
+  /**
+   * Get the publicly accessible representation of this component - i.e. what
+   * is exposed by refs and returned by React.render. Can be null for stateless
+   * components.
+   *
+   * @return {ReactComponent} the public component instance.
+   * @internal
+   */
+  getPublicInstance: function() {
+    return this._instance;
+  },
+
+  // Stub
+  _instantiateReactComponent: null
+
+};
+
+ReactPerf.measureMethods(
+  ReactCompositeComponentMixin,
+  'ReactCompositeComponent',
+  {
+    mountComponent: 'mountComponent',
+    updateComponent: 'updateComponent',
+    _renderValidatedComponent: '_renderValidatedComponent'
+  }
+);
+
+var ReactCompositeComponent = {
+
+  Mixin: ReactCompositeComponentMixin
+
+};
+
+module.exports = ReactCompositeComponent;
+
+},{"115":115,"135":135,"151":151,"154":154,"27":27,"36":36,"38":38,"39":39,"57":57,"58":58,"67":67,"68":68,"73":73,"75":75,"76":76,"77":77,"81":81,"87":87}],38:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactContext
+ */
+
+'use strict';
+
+var assign = _dereq_(27);
+var emptyObject = _dereq_(115);
+var warning = _dereq_(154);
+
+var didWarn = false;
+
+/**
+ * Keeps track of the current context.
+ *
+ * The context is automatically passed down the component ownership hierarchy
+ * and is accessible via `this.context` on ReactCompositeComponents.
+ */
+var ReactContext = {
+
+  /**
+   * @internal
+   * @type {object}
+   */
+  current: emptyObject,
+
+  /**
+   * Temporarily extends the current context while executing scopedCallback.
+   *
+   * A typical use case might look like
+   *
+   *  render: function() {
+   *    var children = ReactContext.withContext({foo: 'foo'}, () => (
+   *
+   *    ));
+   *    return <div>{children}</div>;
+   *  }
+   *
+   * @param {object} newContext New context to merge into the existing context
+   * @param {function} scopedCallback Callback to run with the new context
+   * @return {ReactComponent|array<ReactComponent>}
+   */
+  withContext: function(newContext, scopedCallback) {
+    if ("production" !== "development") {
+      ("production" !== "development" ? warning(
+        didWarn,
+        'withContext is deprecated and will be removed in a future version. ' +
+        'Use a wrapper component with getChildContext instead.'
+      ) : null);
+
+      didWarn = true;
+    }
+
+    var result;
+    var previousContext = ReactContext.current;
+    ReactContext.current = assign({}, previousContext, newContext);
+    try {
+      result = scopedCallback();
+    } finally {
+      ReactContext.current = previousContext;
+    }
+    return result;
+  }
+
+};
+
+module.exports = ReactContext;
+
+},{"115":115,"154":154,"27":27}],39:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCurrentOwner
+ */
+
+'use strict';
+
+/**
+ * Keeps track of the current owner.
+ *
+ * The current owner is the component who should own any components that are
+ * currently being constructed.
+ *
+ * The depth indicate how many composite components are above this render level.
+ */
+var ReactCurrentOwner = {
+
+  /**
+   * @internal
+   * @type {ReactComponent}
+   */
+  current: null
+
+};
+
+module.exports = ReactCurrentOwner;
+
+},{}],40:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOM
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactElementValidator = _dereq_(58);
+
+var mapObject = _dereq_(142);
+
+/**
+ * Create a factory that creates HTML tag elements.
+ *
+ * @param {string} tag Tag name (e.g. `div`).
+ * @private
+ */
+function createDOMFactory(tag) {
+  if ("production" !== "development") {
+    return ReactElementValidator.createFactory(tag);
+  }
+  return ReactElement.createFactory(tag);
+}
+
+/**
+ * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
+ * This is also accessible via `React.DOM`.
+ *
+ * @public
+ */
+var ReactDOM = mapObject({
+  a: 'a',
+  abbr: 'abbr',
+  address: 'address',
+  area: 'area',
+  article: 'article',
+  aside: 'aside',
+  audio: 'audio',
+  b: 'b',
+  base: 'base',
+  bdi: 'bdi',
+  bdo: 'bdo',
+  big: 'big',
+  blockquote: 'blockquote',
+  body: 'body',
+  br: 'br',
+  button: 'button',
+  canvas: 'canvas',
+  caption: 'caption',
+  cite: 'cite',
+  code: 'code',
+  col: 'col',
+  colgroup: 'colgroup',
+  data: 'data',
+  datalist: 'datalist',
+  dd: 'dd',
+  del: 'del',
+  details: 'details',
+  dfn: 'dfn',
+  dialog: 'dialog',
+  div: 'div',
+  dl: 'dl',
+  dt: 'dt',
+  em: 'em',
+  embed: 'embed',
+  fieldset: 'fieldset',
+  figcaption: 'figcaption',
+  figure: 'figure',
+  footer: 'footer',
+  form: 'form',
+  h1: 'h1',
+  h2: 'h2',
+  h3: 'h3',
+  h4: 'h4',
+  h5: 'h5',
+  h6: 'h6',
+  head: 'head',
+  header: 'header',
+  hr: 'hr',
+  html: 'html',
+  i: 'i',
+  iframe: 'iframe',
+  img: 'img',
+  input: 'input',
+  ins: 'ins',
+  kbd: 'kbd',
+  keygen: 'keygen',
+  label: 'label',
+  legend: 'legend',
+  li: 'li',
+  link: 'link',
+  main: 'main',
+  map: 'map',
+  mark: 'mark',
+  menu: 'menu',
+  menuitem: 'menuitem',
+  meta: 'meta',
+  meter: 'meter',
+  nav: 'nav',
+  noscript: 'noscript',
+  object: 'object',
+  ol: 'ol',
+  optgroup: 'optgroup',
+  option: 'option',
+  output: 'output',
+  p: 'p',
+  param: 'param',
+  picture: 'picture',
+  pre: 'pre',
+  progress: 'progress',
+  q: 'q',
+  rp: 'rp',
+  rt: 'rt',
+  ruby: 'ruby',
+  s: 's',
+  samp: 'samp',
+  script: 'script',
+  section: 'section',
+  select: 'select',
+  small: 'small',
+  source: 'source',
+  span: 'span',
+  strong: 'strong',
+  style: 'style',
+  sub: 'sub',
+  summary: 'summary',
+  sup: 'sup',
+  table: 'table',
+  tbody: 'tbody',
+  td: 'td',
+  textarea: 'textarea',
+  tfoot: 'tfoot',
+  th: 'th',
+  thead: 'thead',
+  time: 'time',
+  title: 'title',
+  tr: 'tr',
+  track: 'track',
+  u: 'u',
+  ul: 'ul',
+  'var': 'var',
+  video: 'video',
+  wbr: 'wbr',
+
+  // SVG
+  circle: 'circle',
+  defs: 'defs',
+  ellipse: 'ellipse',
+  g: 'g',
+  line: 'line',
+  linearGradient: 'linearGradient',
+  mask: 'mask',
+  path: 'path',
+  pattern: 'pattern',
+  polygon: 'polygon',
+  polyline: 'polyline',
+  radialGradient: 'radialGradient',
+  rect: 'rect',
+  stop: 'stop',
+  svg: 'svg',
+  text: 'text',
+  tspan: 'tspan'
+
+}, createDOMFactory);
+
+module.exports = ReactDOM;
+
+},{"142":142,"57":57,"58":58}],41:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMButton
+ */
+
+'use strict';
+
+var AutoFocusMixin = _dereq_(2);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var keyMirror = _dereq_(140);
+
+var button = ReactElement.createFactory('button');
+
+var mouseListenerNames = keyMirror({
+  onClick: true,
+  onDoubleClick: true,
+  onMouseDown: true,
+  onMouseMove: true,
+  onMouseUp: true,
+  onClickCapture: true,
+  onDoubleClickCapture: true,
+  onMouseDownCapture: true,
+  onMouseMoveCapture: true,
+  onMouseUpCapture: true
+});
+
+/**
+ * Implements a <button> native component that does not receive mouse events
+ * when `disabled` is set.
+ */
+var ReactDOMButton = ReactClass.createClass({
+  displayName: 'ReactDOMButton',
+  tagName: 'BUTTON',
+
+  mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
+
+  render: function() {
+    var props = {};
+
+    // Copy the props; except the mouse listeners if we're disabled
+    for (var key in this.props) {
+      if (this.props.hasOwnProperty(key) &&
+          (!this.props.disabled || !mouseListenerNames[key])) {
+        props[key] = this.props[key];
+      }
+    }
+
+    return button(props, this.props.children);
+  }
+
+});
+
+module.exports = ReactDOMButton;
+
+},{"140":140,"2":2,"29":29,"33":33,"57":57}],42:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMComponent
+ * @typechecks static-only
+ */
+
+/* global hasOwnProperty:true */
+
+'use strict';
+
+var CSSPropertyOperations = _dereq_(5);
+var DOMProperty = _dereq_(10);
+var DOMPropertyOperations = _dereq_(11);
+var ReactBrowserEventEmitter = _dereq_(30);
+var ReactComponentBrowserEnvironment =
+  _dereq_(35);
+var ReactMount = _dereq_(70);
+var ReactMultiChild = _dereq_(71);
+var ReactPerf = _dereq_(75);
+
+var assign = _dereq_(27);
+var escapeTextContentForBrowser = _dereq_(116);
+var invariant = _dereq_(135);
+var isEventSupported = _dereq_(136);
+var keyOf = _dereq_(141);
+var warning = _dereq_(154);
+
+var deleteListener = ReactBrowserEventEmitter.deleteListener;
+var listenTo = ReactBrowserEventEmitter.listenTo;
+var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
+
+// For quickly matching children type, to test if can be treated as content.
+var CONTENT_TYPES = {'string': true, 'number': true};
+
+var STYLE = keyOf({style: null});
+
+var ELEMENT_NODE_TYPE = 1;
+
+/**
+ * Optionally injectable operations for mutating the DOM
+ */
+var BackendIDOperations = null;
+
+/**
+ * @param {?object} props
+ */
+function assertValidProps(props) {
+  if (!props) {
+    return;
+  }
+  // Note the use of `==` which checks for null or undefined.
+  if (props.dangerouslySetInnerHTML != null) {
+    ("production" !== "development" ? invariant(
+      props.children == null,
+      'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+    ) : invariant(props.children == null));
+    ("production" !== "development" ? invariant(
+      props.dangerouslySetInnerHTML.__html != null,
+      '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
+      'Please visit http://fb.me/react-invariant-dangerously-set-inner-html ' +
+      'for more information.'
+    ) : invariant(props.dangerouslySetInnerHTML.__html != null));
+  }
+  if ("production" !== "development") {
+    ("production" !== "development" ? warning(
+      props.innerHTML == null,
+      'Directly setting property `innerHTML` is not permitted. ' +
+      'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+    ) : null);
+    ("production" !== "development" ? warning(
+      !props.contentEditable || props.children == null,
+      'A component is `contentEditable` and contains `children` managed by ' +
+      'React. It is now your responsibility to guarantee that none of ' +
+      'those nodes are unexpectedly modified or duplicated. This is ' +
+      'probably not intentional.'
+    ) : null);
+  }
+  ("production" !== "development" ? invariant(
+    props.style == null || typeof props.style === 'object',
+    'The `style` prop expects a mapping from style properties to values, ' +
+    'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
+    'using JSX.'
+  ) : invariant(props.style == null || typeof props.style === 'object'));
+}
+
+function putListener(id, registrationName, listener, transaction) {
+  if ("production" !== "development") {
+    // IE8 has no API for event capturing and the `onScroll` event doesn't
+    // bubble.
+    ("production" !== "development" ? warning(
+      registrationName !== 'onScroll' || isEventSupported('scroll', true),
+      'This browser doesn\'t support the `onScroll` event'
+    ) : null);
+  }
+  var container = ReactMount.findReactContainerForID(id);
+  if (container) {
+    var doc = container.nodeType === ELEMENT_NODE_TYPE ?
+      container.ownerDocument :
+      container;
+    listenTo(registrationName, doc);
+  }
+  transaction.getPutListenerQueue().enqueuePutListener(
+    id,
+    registrationName,
+    listener
+  );
+}
+
+// For HTML, certain tags should omit their close tag. We keep a whitelist for
+// those special cased tags.
+
+var omittedCloseTags = {
+  'area': true,
+  'base': true,
+  'br': true,
+  'col': true,
+  'embed': true,
+  'hr': true,
+  'img': true,
+  'input': true,
+  'keygen': true,
+  'link': true,
+  'meta': true,
+  'param': true,
+  'source': true,
+  'track': true,
+  'wbr': true
+  // NOTE: menuitem's close tag should be omitted, but that causes problems.
+};
+
+// We accept any tag to be rendered but since this gets injected into abitrary
+// HTML, we want to make sure that it's a safe tag.
+// http://www.w3.org/TR/REC-xml/#NT-Name
+
+var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
+var validatedTagCache = {};
+var hasOwnProperty = {}.hasOwnProperty;
+
+function validateDangerousTag(tag) {
+  if (!hasOwnProperty.call(validatedTagCache, tag)) {
+    ("production" !== "development" ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
+    validatedTagCache[tag] = true;
+  }
+}
+
+/**
+ * Creates a new React class that is idempotent and capable of containing other
+ * React components. It accepts event listeners and DOM properties that are
+ * valid according to `DOMProperty`.
+ *
+ *  - Event listeners: `onClick`, `onMouseDown`, etc.
+ *  - DOM properties: `className`, `name`, `title`, etc.
+ *
+ * The `style` property functions differently from the DOM API. It accepts an
+ * object mapping of style properties to values.
+ *
+ * @constructor ReactDOMComponent
+ * @extends ReactMultiChild
+ */
+function ReactDOMComponent(tag) {
+  validateDangerousTag(tag);
+  this._tag = tag;
+  this._renderedChildren = null;
+  this._previousStyleCopy = null;
+  this._rootNodeID = null;
+}
+
+ReactDOMComponent.displayName = 'ReactDOMComponent';
+
+ReactDOMComponent.Mixin = {
+
+  construct: function(element) {
+    this._currentElement = element;
+  },
+
+  /**
+   * Generates root tag markup then recurses. This method has side effects and
+   * is not idempotent.
+   *
+   * @internal
+   * @param {string} rootID The root DOM ID for this node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} The computed markup.
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._rootNodeID = rootID;
+    assertValidProps(this._currentElement.props);
+    var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
+    return (
+      this._createOpenTagMarkupAndPutListeners(transaction) +
+      this._createContentMarkup(transaction, context) +
+      closeTag
+    );
+  },
+
+  /**
+   * Creates markup for the open tag and all attributes.
+   *
+   * This method has side effects because events get registered.
+   *
+   * Iterating over object properties is faster than iterating over arrays.
+   * @see http://jsperf.com/obj-vs-arr-iteration
+   *
+   * @private
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} Markup of opening tag.
+   */
+  _createOpenTagMarkupAndPutListeners: function(transaction) {
+    var props = this._currentElement.props;
+    var ret = '<' + this._tag;
+
+    for (var propKey in props) {
+      if (!props.hasOwnProperty(propKey)) {
+        continue;
+      }
+      var propValue = props[propKey];
+      if (propValue == null) {
+        continue;
+      }
+      if (registrationNameModules.hasOwnProperty(propKey)) {
+        putListener(this._rootNodeID, propKey, propValue, transaction);
+      } else {
+        if (propKey === STYLE) {
+          if (propValue) {
+            propValue = this._previousStyleCopy = assign({}, props.style);
+          }
+          propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
+        }
+        var markup =
+          DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
+        if (markup) {
+          ret += ' ' + markup;
+        }
+      }
+    }
+
+    // For static pages, no need to put React ID and checksum. Saves lots of
+    // bytes.
+    if (transaction.renderToStaticMarkup) {
+      return ret + '>';
+    }
+
+    var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
+    return ret + ' ' + markupForID + '>';
+  },
+
+  /**
+   * Creates markup for the content between the tags.
+   *
+   * @private
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @param {object} context
+   * @return {string} Content markup.
+   */
+  _createContentMarkup: function(transaction, context) {
+    var prefix = '';
+    if (this._tag === 'listing' ||
+        this._tag === 'pre' ||
+        this._tag === 'textarea') {
+      // Add an initial newline because browsers ignore the first newline in
+      // a <listing>, <pre>, or <textarea> as an "authoring convenience" -- see
+      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody.
+      prefix = '\n';
+    }
+
+    var props = this._currentElement.props;
+
+    // Intentional use of != to avoid catching zero/false.
+    var innerHTML = props.dangerouslySetInnerHTML;
+    if (innerHTML != null) {
+      if (innerHTML.__html != null) {
+        return prefix + innerHTML.__html;
+      }
+    } else {
+      var contentToUse =
+        CONTENT_TYPES[typeof props.children] ? props.children : null;
+      var childrenToUse = contentToUse != null ? null : props.children;
+      if (contentToUse != null) {
+        return prefix + escapeTextContentForBrowser(contentToUse);
+      } else if (childrenToUse != null) {
+        var mountImages = this.mountChildren(
+          childrenToUse,
+          transaction,
+          context
+        );
+        return prefix + mountImages.join('');
+      }
+    }
+    return prefix;
+  },
+
+  receiveComponent: function(nextElement, transaction, context) {
+    var prevElement = this._currentElement;
+    this._currentElement = nextElement;
+    this.updateComponent(transaction, prevElement, nextElement, context);
+  },
+
+  /**
+   * Updates a native DOM component after it has already been allocated and
+   * attached to the DOM. Reconciles the root DOM node, then recurses.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @param {ReactElement} prevElement
+   * @param {ReactElement} nextElement
+   * @internal
+   * @overridable
+   */
+  updateComponent: function(transaction, prevElement, nextElement, context) {
+    assertValidProps(this._currentElement.props);
+    this._updateDOMProperties(prevElement.props, transaction);
+    this._updateDOMChildren(prevElement.props, transaction, context);
+  },
+
+  /**
+   * Reconciles the properties by detecting differences in property values and
+   * updating the DOM as necessary. This function is probably the single most
+   * critical path for performance optimization.
+   *
+   * TODO: Benchmark whether checking for changed values in memory actually
+   *       improves performance (especially statically positioned elements).
+   * TODO: Benchmark the effects of putting this at the top since 99% of props
+   *       do not change for a given reconciliation.
+   * TODO: Benchmark areas that can be improved with caching.
+   *
+   * @private
+   * @param {object} lastProps
+   * @param {ReactReconcileTransaction} transaction
+   */
+  _updateDOMProperties: function(lastProps, transaction) {
+    var nextProps = this._currentElement.props;
+    var propKey;
+    var styleName;
+    var styleUpdates;
+    for (propKey in lastProps) {
+      if (nextProps.hasOwnProperty(propKey) ||
+         !lastProps.hasOwnProperty(propKey)) {
+        continue;
+      }
+      if (propKey === STYLE) {
+        var lastStyle = this._previousStyleCopy;
+        for (styleName in lastStyle) {
+          if (lastStyle.hasOwnProperty(styleName)) {
+            styleUpdates = styleUpdates || {};
+            styleUpdates[styleName] = '';
+          }
+        }
+      } else if (registrationNameModules.hasOwnProperty(propKey)) {
+        deleteListener(this._rootNodeID, propKey);
+      } else if (
+          DOMProperty.isStandardName[propKey] ||
+          DOMProperty.isCustomAttribute(propKey)) {
+        BackendIDOperations.deletePropertyByID(
+          this._rootNodeID,
+          propKey
+        );
+      }
+    }
+    for (propKey in nextProps) {
+      var nextProp = nextProps[propKey];
+      var lastProp = propKey === STYLE ?
+        this._previousStyleCopy :
+        lastProps[propKey];
+      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
+        continue;
+      }
+      if (propKey === STYLE) {
+        if (nextProp) {
+          nextProp = this._previousStyleCopy = assign({}, nextProp);
+        }
+        if (lastProp) {
+          // Unset styles on `lastProp` but not on `nextProp`.
+          for (styleName in lastProp) {
+            if (lastProp.hasOwnProperty(styleName) &&
+                (!nextProp || !nextProp.hasOwnProperty(styleName))) {
+              styleUpdates = styleUpdates || {};
+              styleUpdates[styleName] = '';
+            }
+          }
+          // Update styles that changed since `lastProp`.
+          for (styleName in nextProp) {
+            if (nextProp.hasOwnProperty(styleName) &&
+                lastProp[styleName] !== nextProp[styleName]) {
+              styleUpdates = styleUpdates || {};
+              styleUpdates[styleName] = nextProp[styleName];
+            }
+          }
+        } else {
+          // Relies on `updateStylesByID` not mutating `styleUpdates`.
+          styleUpdates = nextProp;
+        }
+      } else if (registrationNameModules.hasOwnProperty(propKey)) {
+        putListener(this._rootNodeID, propKey, nextProp, transaction);
+      } else if (
+          DOMProperty.isStandardName[propKey] ||
+          DOMProperty.isCustomAttribute(propKey)) {
+        BackendIDOperations.updatePropertyByID(
+          this._rootNodeID,
+          propKey,
+          nextProp
+        );
+      }
+    }
+    if (styleUpdates) {
+      BackendIDOperations.updateStylesByID(
+        this._rootNodeID,
+        styleUpdates
+      );
+    }
+  },
+
+  /**
+   * Reconciles the children with the various properties that affect the
+   * children content.
+   *
+   * @param {object} lastProps
+   * @param {ReactReconcileTransaction} transaction
+   */
+  _updateDOMChildren: function(lastProps, transaction, context) {
+    var nextProps = this._currentElement.props;
+
+    var lastContent =
+      CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
+    var nextContent =
+      CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
+
+    var lastHtml =
+      lastProps.dangerouslySetInnerHTML &&
+      lastProps.dangerouslySetInnerHTML.__html;
+    var nextHtml =
+      nextProps.dangerouslySetInnerHTML &&
+      nextProps.dangerouslySetInnerHTML.__html;
+
+    // Note the use of `!=` which checks for null or undefined.
+    var lastChildren = lastContent != null ? null : lastProps.children;
+    var nextChildren = nextContent != null ? null : nextProps.children;
+
+    // If we're switching from children to content/html or vice versa, remove
+    // the old content
+    var lastHasContentOrHtml = lastContent != null || lastHtml != null;
+    var nextHasContentOrHtml = nextContent != null || nextHtml != null;
+    if (lastChildren != null && nextChildren == null) {
+      this.updateChildren(null, transaction, context);
+    } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
+      this.updateTextContent('');
+    }
+
+    if (nextContent != null) {
+      if (lastContent !== nextContent) {
+        this.updateTextContent('' + nextContent);
+      }
+    } else if (nextHtml != null) {
+      if (lastHtml !== nextHtml) {
+        BackendIDOperations.updateInnerHTMLByID(
+          this._rootNodeID,
+          nextHtml
+        );
+      }
+    } else if (nextChildren != null) {
+      this.updateChildren(nextChildren, transaction, context);
+    }
+  },
+
+  /**
+   * Destroys all event registrations for this instance. Does not remove from
+   * the DOM. That must be done by the parent.
+   *
+   * @internal
+   */
+  unmountComponent: function() {
+    this.unmountChildren();
+    ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
+    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
+    this._rootNodeID = null;
+  }
+
+};
+
+ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
+  mountComponent: 'mountComponent',
+  updateComponent: 'updateComponent'
+});
+
+assign(
+  ReactDOMComponent.prototype,
+  ReactDOMComponent.Mixin,
+  ReactMultiChild.Mixin
+);
+
+ReactDOMComponent.injection = {
+  injectIDOperations: function(IDOperations) {
+    ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
+  }
+};
+
+module.exports = ReactDOMComponent;
+
+},{"10":10,"11":11,"116":116,"135":135,"136":136,"141":141,"154":154,"27":27,"30":30,"35":35,"5":5,"70":70,"71":71,"75":75}],43:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMForm
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var LocalEventTrapMixin = _dereq_(25);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var form = ReactElement.createFactory('form');
+
+/**
+ * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
+ * to capture it on the <form> element itself. There are lots of hacks we could
+ * do to accomplish this, but the most reliable is to make <form> a
+ * composite component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMForm = ReactClass.createClass({
+  displayName: 'ReactDOMForm',
+  tagName: 'FORM',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
+    // `jshint` fails to parse JSX so in order for linting to work in the open
+    // source repo, we need to just use `ReactDOM.form`.
+    return form(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
+  }
+});
+
+module.exports = ReactDOMForm;
+
+},{"15":15,"25":25,"29":29,"33":33,"57":57}],44:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMIDOperations
+ * @typechecks static-only
+ */
+
+/*jslint evil: true */
+
+'use strict';
+
+var CSSPropertyOperations = _dereq_(5);
+var DOMChildrenOperations = _dereq_(9);
+var DOMPropertyOperations = _dereq_(11);
+var ReactMount = _dereq_(70);
+var ReactPerf = _dereq_(75);
+
+var invariant = _dereq_(135);
+var setInnerHTML = _dereq_(148);
+
+/**
+ * Errors for properties that should not be updated with `updatePropertyById()`.
+ *
+ * @type {object}
+ * @private
+ */
+var INVALID_PROPERTY_ERRORS = {
+  dangerouslySetInnerHTML:
+    '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
+  style: '`style` must be set using `updateStylesByID()`.'
+};
+
+/**
+ * Operations used to process updates to DOM nodes. This is made injectable via
+ * `ReactDOMComponent.BackendIDOperations`.
+ */
+var ReactDOMIDOperations = {
+
+  /**
+   * Updates a DOM node with new property values. This should only be used to
+   * update DOM properties in `DOMProperty`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} name A valid property name, see `DOMProperty`.
+   * @param {*} value New value of the property.
+   * @internal
+   */
+  updatePropertyByID: function(id, name, value) {
+    var node = ReactMount.getNode(id);
+    ("production" !== "development" ? invariant(
+      !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+      'updatePropertyByID(...): %s',
+      INVALID_PROPERTY_ERRORS[name]
+    ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+
+    // If we're updating to null or undefined, we should remove the property
+    // from the DOM node instead of inadvertantly setting to a string. This
+    // brings us in line with the same behavior we have on initial render.
+    if (value != null) {
+      DOMPropertyOperations.setValueForProperty(node, name, value);
+    } else {
+      DOMPropertyOperations.deleteValueForProperty(node, name);
+    }
+  },
+
+  /**
+   * Updates a DOM node to remove a property. This should only be used to remove
+   * DOM properties in `DOMProperty`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} name A property name to remove, see `DOMProperty`.
+   * @internal
+   */
+  deletePropertyByID: function(id, name, value) {
+    var node = ReactMount.getNode(id);
+    ("production" !== "development" ? invariant(
+      !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+      'updatePropertyByID(...): %s',
+      INVALID_PROPERTY_ERRORS[name]
+    ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+    DOMPropertyOperations.deleteValueForProperty(node, name, value);
+  },
+
+  /**
+   * Updates a DOM node with new style values. If a value is specified as '',
+   * the corresponding style property will be unset.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {object} styles Mapping from styles to values.
+   * @internal
+   */
+  updateStylesByID: function(id, styles) {
+    var node = ReactMount.getNode(id);
+    CSSPropertyOperations.setValueForStyles(node, styles);
+  },
+
+  /**
+   * Updates a DOM node's innerHTML.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} html An HTML string.
+   * @internal
+   */
+  updateInnerHTMLByID: function(id, html) {
+    var node = ReactMount.getNode(id);
+    setInnerHTML(node, html);
+  },
+
+  /**
+   * Updates a DOM node's text content set by `props.content`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} content Text content.
+   * @internal
+   */
+  updateTextContentByID: function(id, content) {
+    var node = ReactMount.getNode(id);
+    DOMChildrenOperations.updateTextContent(node, content);
+  },
+
+  /**
+   * Replaces a DOM node that exists in the document with markup.
+   *
+   * @param {string} id ID of child to be replaced.
+   * @param {string} markup Dangerous markup to inject in place of child.
+   * @internal
+   * @see {Danger.dangerouslyReplaceNodeWithMarkup}
+   */
+  dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
+    var node = ReactMount.getNode(id);
+    DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
+  },
+
+  /**
+   * Updates a component's children by processing a series of updates.
+   *
+   * @param {array<object>} updates List of update configurations.
+   * @param {array<string>} markup List of markup strings.
+   * @internal
+   */
+  dangerouslyProcessChildrenUpdates: function(updates, markup) {
+    for (var i = 0; i < updates.length; i++) {
+      updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
+    }
+    DOMChildrenOperations.processUpdates(updates, markup);
+  }
+};
+
+ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
+  updatePropertyByID: 'updatePropertyByID',
+  deletePropertyByID: 'deletePropertyByID',
+  updateStylesByID: 'updateStylesByID',
+  updateInnerHTMLByID: 'updateInnerHTMLByID',
+  updateTextContentByID: 'updateTextContentByID',
+  dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
+  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
+});
+
+module.exports = ReactDOMIDOperations;
+
+},{"11":11,"135":135,"148":148,"5":5,"70":70,"75":75,"9":9}],45:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMIframe
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var LocalEventTrapMixin = _dereq_(25);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var iframe = ReactElement.createFactory('iframe');
+
+/**
+ * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
+ * capture it on the <iframe> element itself. There are lots of hacks we could
+ * do to accomplish this, but the most reliable is to make <iframe> a composite
+ * component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMIframe = ReactClass.createClass({
+  displayName: 'ReactDOMIframe',
+  tagName: 'IFRAME',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    return iframe(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
+  }
+});
+
+module.exports = ReactDOMIframe;
+
+},{"15":15,"25":25,"29":29,"33":33,"57":57}],46:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMImg
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var LocalEventTrapMixin = _dereq_(25);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var img = ReactElement.createFactory('img');
+
+/**
+ * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
+ * capture it on the <img> element itself. There are lots of hacks we could do
+ * to accomplish this, but the most reliable is to make <img> a composite
+ * component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMImg = ReactClass.createClass({
+  displayName: 'ReactDOMImg',
+  tagName: 'IMG',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    return img(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
+  }
+});
+
+module.exports = ReactDOMImg;
+
+},{"15":15,"25":25,"29":29,"33":33,"57":57}],47:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMInput
+ */
+
+'use strict';
+
+var AutoFocusMixin = _dereq_(2);
+var DOMPropertyOperations = _dereq_(11);
+var LinkedValueUtils = _dereq_(24);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+var ReactMount = _dereq_(70);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+
+var input = ReactElement.createFactory('input');
+
+var instancesByReactID = {};
+
+function forceUpdateIfMounted() {
+  /*jshint validthis:true */
+  if (this.isMounted()) {
+    this.forceUpdate();
+  }
+}
+
+/**
+ * Implements an <input> native component that allows setting these optional
+ * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
+ *
+ * If `checked` or `value` are not supplied (or null/undefined), user actions
+ * that affect the checked state or value will trigger updates to the element.
+ *
+ * If they are supplied (and not null/undefined), the rendered element will not
+ * trigger updates to the element. Instead, the props must change in order for
+ * the rendered element to be updated.
+ *
+ * The rendered element will be initialized as unchecked (or `defaultChecked`)
+ * with an empty value (or `defaultValue`).
+ *
+ * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
+ */
+var ReactDOMInput = ReactClass.createClass({
+  displayName: 'ReactDOMInput',
+  tagName: 'INPUT',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  getInitialState: function() {
+    var defaultValue = this.props.defaultValue;
+    return {
+      initialChecked: this.props.defaultChecked || false,
+      initialValue: defaultValue != null ? defaultValue : null
+    };
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    props.defaultChecked = null;
+    props.defaultValue = null;
+
+    var value = LinkedValueUtils.getValue(this);
+    props.value = value != null ? value : this.state.initialValue;
+
+    var checked = LinkedValueUtils.getChecked(this);
+    props.checked = checked != null ? checked : this.state.initialChecked;
+
+    props.onChange = this._handleChange;
+
+    return input(props, this.props.children);
+  },
+
+  componentDidMount: function() {
+    var id = ReactMount.getID(this.getDOMNode());
+    instancesByReactID[id] = this;
+  },
+
+  componentWillUnmount: function() {
+    var rootNode = this.getDOMNode();
+    var id = ReactMount.getID(rootNode);
+    delete instancesByReactID[id];
+  },
+
+  componentDidUpdate: function(prevProps, prevState, prevContext) {
+    var rootNode = this.getDOMNode();
+    if (this.props.checked != null) {
+      DOMPropertyOperations.setValueForProperty(
+        rootNode,
+        'checked',
+        this.props.checked || false
+      );
+    }
+
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      // Cast `value` to a string to ensure the value is set correctly. While
+      // browsers typically do this as necessary, jsdom doesn't.
+      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+    // Here we use asap to wait until all updates have propagated, which
+    // is important when using controlled components within layers:
+    // https://github.com/facebook/react/issues/1698
+    ReactUpdates.asap(forceUpdateIfMounted, this);
+
+    var name = this.props.name;
+    if (this.props.type === 'radio' && name != null) {
+      var rootNode = this.getDOMNode();
+      var queryRoot = rootNode;
+
+      while (queryRoot.parentNode) {
+        queryRoot = queryRoot.parentNode;
+      }
+
+      // If `rootNode.form` was non-null, then we could try `form.elements`,
+      // but that sometimes behaves strangely in IE8. We could also try using
+      // `form.getElementsByName`, but that will only return direct children
+      // and won't include inputs that use the HTML5 `form=` attribute. Since
+      // the input might not even be in a form, let's just use the global
+      // `querySelectorAll` to ensure we don't miss anything.
+      var group = queryRoot.querySelectorAll(
+        'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
+
+      for (var i = 0, groupLen = group.length; i < groupLen; i++) {
+        var otherNode = group[i];
+        if (otherNode === rootNode ||
+            otherNode.form !== rootNode.form) {
+          continue;
+        }
+        var otherID = ReactMount.getID(otherNode);
+        ("production" !== "development" ? invariant(
+          otherID,
+          'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
+          'same `name` is not supported.'
+        ) : invariant(otherID));
+        var otherInstance = instancesByReactID[otherID];
+        ("production" !== "development" ? invariant(
+          otherInstance,
+          'ReactDOMInput: Unknown radio button ID %s.',
+          otherID
+        ) : invariant(otherInstance));
+        // If this is a controlled radio button group, forcing the input that
+        // was previously checked to update will cause it to be come re-checked
+        // as appropriate.
+        ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
+      }
+    }
+
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMInput;
+
+},{"11":11,"135":135,"2":2,"24":24,"27":27,"29":29,"33":33,"57":57,"70":70,"87":87}],48:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMOption
+ */
+
+'use strict';
+
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var warning = _dereq_(154);
+
+var option = ReactElement.createFactory('option');
+
+/**
+ * Implements an <option> native component that warns when `selected` is set.
+ */
+var ReactDOMOption = ReactClass.createClass({
+  displayName: 'ReactDOMOption',
+  tagName: 'OPTION',
+
+  mixins: [ReactBrowserComponentMixin],
+
+  componentWillMount: function() {
+    // TODO (yungsters): Remove support for `selected` in <option>.
+    if ("production" !== "development") {
+      ("production" !== "development" ? warning(
+        this.props.selected == null,
+        'Use the `defaultValue` or `value` props on <select> instead of ' +
+        'setting `selected` on <option>.'
+      ) : null);
+    }
+  },
+
+  render: function() {
+    return option(this.props, this.props.children);
+  }
+
+});
+
+module.exports = ReactDOMOption;
+
+},{"154":154,"29":29,"33":33,"57":57}],49:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelect
+ */
+
+'use strict';
+
+var AutoFocusMixin = _dereq_(2);
+var LinkedValueUtils = _dereq_(24);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+
+var select = ReactElement.createFactory('select');
+
+function updateOptionsIfPendingUpdateAndMounted() {
+  /*jshint validthis:true */
+  if (this._pendingUpdate) {
+    this._pendingUpdate = false;
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null && this.isMounted()) {
+      updateOptions(this, value);
+    }
+  }
+}
+
+/**
+ * Validation function for `value` and `defaultValue`.
+ * @private
+ */
+function selectValueType(props, propName, componentName) {
+  if (props[propName] == null) {
+    return null;
+  }
+  if (props.multiple) {
+    if (!Array.isArray(props[propName])) {
+      return new Error(
+        ("The `" + propName + "` prop supplied to <select> must be an array if ") +
+        ("`multiple` is true.")
+      );
+    }
+  } else {
+    if (Array.isArray(props[propName])) {
+      return new Error(
+        ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
+        ("value if `multiple` is false.")
+      );
+    }
+  }
+}
+
+/**
+ * @param {ReactComponent} component Instance of ReactDOMSelect
+ * @param {*} propValue A stringable (with `multiple`, a list of stringables).
+ * @private
+ */
+function updateOptions(component, propValue) {
+  var selectedValue, i, l;
+  var options = component.getDOMNode().options;
+
+  if (component.props.multiple) {
+    selectedValue = {};
+    for (i = 0, l = propValue.length; i < l; i++) {
+      selectedValue['' + propValue[i]] = true;
+    }
+    for (i = 0, l = options.length; i < l; i++) {
+      var selected = selectedValue.hasOwnProperty(options[i].value);
+      if (options[i].selected !== selected) {
+        options[i].selected = selected;
+      }
+    }
+  } else {
+    // Do not set `select.value` as exact behavior isn't consistent across all
+    // browsers for all cases.
+    selectedValue = '' + propValue;
+    for (i = 0, l = options.length; i < l; i++) {
+      if (options[i].value === selectedValue) {
+        options[i].selected = true;
+        return;
+      }
+    }
+    options[0].selected = true;
+  }
+}
+
+/**
+ * Implements a <select> native component that allows optionally setting the
+ * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
+ * stringable. If `multiple` is true, the prop must be an array of stringables.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that change the
+ * selected option will trigger updates to the rendered options.
+ *
+ * If it is supplied (and not null/undefined), the rendered options will not
+ * update in response to user actions. Instead, the `value` prop must change in
+ * order for the rendered options to update.
+ *
+ * If `defaultValue` is provided, any options with the supplied values will be
+ * selected.
+ */
+var ReactDOMSelect = ReactClass.createClass({
+  displayName: 'ReactDOMSelect',
+  tagName: 'SELECT',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  propTypes: {
+    defaultValue: selectValueType,
+    value: selectValueType
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    props.onChange = this._handleChange;
+    props.value = null;
+
+    return select(props, this.props.children);
+  },
+
+  componentWillMount: function() {
+    this._pendingUpdate = false;
+  },
+
+  componentDidMount: function() {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      updateOptions(this, value);
+    } else if (this.props.defaultValue != null) {
+      updateOptions(this, this.props.defaultValue);
+    }
+  },
+
+  componentDidUpdate: function(prevProps) {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      this._pendingUpdate = false;
+      updateOptions(this, value);
+    } else if (!prevProps.multiple !== !this.props.multiple) {
+      // For simplicity, reapply `defaultValue` if `multiple` is toggled.
+      if (this.props.defaultValue != null) {
+        updateOptions(this, this.props.defaultValue);
+      } else {
+        // Revert the select back to its default unselected state.
+        updateOptions(this, this.props.multiple ? [] : '');
+      }
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+
+    this._pendingUpdate = true;
+    ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMSelect;
+
+},{"2":2,"24":24,"27":27,"29":29,"33":33,"57":57,"87":87}],50:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelection
+ */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+
+var getNodeForCharacterOffset = _dereq_(128);
+var getTextContentAccessor = _dereq_(130);
+
+/**
+ * While `isCollapsed` is available on the Selection object and `collapsed`
+ * is available on the Range object, IE11 sometimes gets them wrong.
+ * If the anchor/focus nodes and offsets are the same, the range is collapsed.
+ */
+function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
+  return anchorNode === focusNode && anchorOffset === focusOffset;
+}
+
+/**
+ * Get the appropriate anchor and focus node/offset pairs for IE.
+ *
+ * The catch here is that IE's selection API doesn't provide information
+ * about whether the selection is forward or backward, so we have to
+ * behave as though it's always forward.
+ *
+ * IE text differs from modern selection in that it behaves as though
+ * block elements end with a new line. This means character offsets will
+ * differ between the two APIs.
+ *
+ * @param {DOMElement} node
+ * @return {object}
+ */
+function getIEOffsets(node) {
+  var selection = document.selection;
+  var selectedRange = selection.createRange();
+  var selectedLength = selectedRange.text.length;
+
+  // Duplicate selection so we can move range without breaking user selection.
+  var fromStart = selectedRange.duplicate();
+  fromStart.moveToElementText(node);
+  fromStart.setEndPoint('EndToStart', selectedRange);
+
+  var startOffset = fromStart.text.length;
+  var endOffset = startOffset + selectedLength;
+
+  return {
+    start: startOffset,
+    end: endOffset
+  };
+}
+
+/**
+ * @param {DOMElement} node
+ * @return {?object}
+ */
+function getModernOffsets(node) {
+  var selection = window.getSelection && window.getSelection();
+
+  if (!selection || selection.rangeCount === 0) {
+    return null;
+  }
+
+  var anchorNode = selection.anchorNode;
+  var anchorOffset = selection.anchorOffset;
+  var focusNode = selection.focusNode;
+  var focusOffset = selection.focusOffset;
+
+  var currentRange = selection.getRangeAt(0);
+
+  // If the node and offset values are the same, the selection is collapsed.
+  // `Selection.isCollapsed` is available natively, but IE sometimes gets
+  // this value wrong.
+  var isSelectionCollapsed = isCollapsed(
+    selection.anchorNode,
+    selection.anchorOffset,
+    selection.focusNode,
+    selection.focusOffset
+  );
+
+  var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
+
+  var tempRange = currentRange.cloneRange();
+  tempRange.selectNodeContents(node);
+  tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);
+
+  var isTempRangeCollapsed = isCollapsed(
+    tempRange.startContainer,
+    tempRange.startOffset,
+    tempRange.endContainer,
+    tempRange.endOffset
+  );
+
+  var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
+  var end = start + rangeLength;
+
+  // Detect whether the selection is backward.
+  var detectionRange = document.createRange();
+  detectionRange.setStart(anchorNode, anchorOffset);
+  detectionRange.setEnd(focusNode, focusOffset);
+  var isBackward = detectionRange.collapsed;
+
+  return {
+    start: isBackward ? end : start,
+    end: isBackward ? start : end
+  };
+}
+
+/**
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setIEOffsets(node, offsets) {
+  var range = document.selection.createRange().duplicate();
+  var start, end;
+
+  if (typeof offsets.end === 'undefined') {
+    start = offsets.start;
+    end = start;
+  } else if (offsets.start > offsets.end) {
+    start = offsets.end;
+    end = offsets.start;
+  } else {
+    start = offsets.start;
+    end = offsets.end;
+  }
+
+  range.moveToElementText(node);
+  range.moveStart('character', start);
+  range.setEndPoint('EndToStart', range);
+  range.moveEnd('character', end - start);
+  range.select();
+}
+
+/**
+ * In modern non-IE browsers, we can support both forward and backward
+ * selections.
+ *
+ * Note: IE10+ supports the Selection object, but it does not support
+ * the `extend` method, which means that even in modern IE, it's not possible
+ * to programatically create a backward selection. Thus, for all IE
+ * versions, we use the old IE API to create our selections.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setModernOffsets(node, offsets) {
+  if (!window.getSelection) {
+    return;
+  }
+
+  var selection = window.getSelection();
+  var length = node[getTextContentAccessor()].length;
+  var start = Math.min(offsets.start, length);
+  var end = typeof offsets.end === 'undefined' ?
+            start : Math.min(offsets.end, length);
+
+  // IE 11 uses modern selection, but doesn't support the extend method.
+  // Flip backward selections, so we can set with a single range.
+  if (!selection.extend && start > end) {
+    var temp = end;
+    end = start;
+    start = temp;
+  }
+
+  var startMarker = getNodeForCharacterOffset(node, start);
+  var endMarker = getNodeForCharacterOffset(node, end);
+
+  if (startMarker && endMarker) {
+    var range = document.createRange();
+    range.setStart(startMarker.node, startMarker.offset);
+    selection.removeAllRanges();
+
+    if (start > end) {
+      selection.addRange(range);
+      selection.extend(endMarker.node, endMarker.offset);
+    } else {
+      range.setEnd(endMarker.node, endMarker.offset);
+      selection.addRange(range);
+    }
+  }
+}
+
+var useIEOffsets = (
+  ExecutionEnvironment.canUseDOM &&
+  'selection' in document &&
+  !('getSelection' in window)
+);
+
+var ReactDOMSelection = {
+  /**
+   * @param {DOMElement} node
+   */
+  getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,
+
+  /**
+   * @param {DOMElement|DOMTextNode} node
+   * @param {object} offsets
+   */
+  setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
+};
+
+module.exports = ReactDOMSelection;
+
+},{"128":128,"130":130,"21":21}],51:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMTextComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMPropertyOperations = _dereq_(11);
+var ReactComponentBrowserEnvironment =
+  _dereq_(35);
+var ReactDOMComponent = _dereq_(42);
+
+var assign = _dereq_(27);
+var escapeTextContentForBrowser = _dereq_(116);
+
+/**
+ * Text nodes violate a couple assumptions that React makes about components:
+ *
+ *  - When mounting text into the DOM, adjacent text nodes are merged.
+ *  - Text nodes cannot be assigned a React root ID.
+ *
+ * This component is used to wrap strings in elements so that they can undergo
+ * the same reconciliation that is applied to elements.
+ *
+ * TODO: Investigate representing React components in the DOM with text nodes.
+ *
+ * @class ReactDOMTextComponent
+ * @extends ReactComponent
+ * @internal
+ */
+var ReactDOMTextComponent = function(props) {
+  // This constructor and its argument is currently used by mocks.
+};
+
+assign(ReactDOMTextComponent.prototype, {
+
+  /**
+   * @param {ReactText} text
+   * @internal
+   */
+  construct: function(text) {
+    // TODO: This is really a ReactText (ReactNode), not a ReactElement
+    this._currentElement = text;
+    this._stringText = '' + text;
+
+    // Properties
+    this._rootNodeID = null;
+    this._mountIndex = 0;
+  },
+
+  /**
+   * Creates the markup for this text node. This node is not intended to have
+   * any features besides containing text content.
+   *
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} Markup for this text node.
+   * @internal
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._rootNodeID = rootID;
+    var escapedText = escapeTextContentForBrowser(this._stringText);
+
+    if (transaction.renderToStaticMarkup) {
+      // Normally we'd wrap this in a `span` for the reasons stated above, but
+      // since this is a situation where React won't take over (static pages),
+      // we can simply return the text as it is.
+      return escapedText;
+    }
+
+    return (
+      '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
+        escapedText +
+      '</span>'
+    );
+  },
+
+  /**
+   * Updates this component by updating the text content.
+   *
+   * @param {ReactText} nextText The next text content
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  receiveComponent: function(nextText, transaction) {
+    if (nextText !== this._currentElement) {
+      this._currentElement = nextText;
+      var nextStringText = '' + nextText;
+      if (nextStringText !== this._stringText) {
+        // TODO: Save this as pending props and use performUpdateIfNecessary
+        // and/or updateComponent to do the actual update for consistency with
+        // other component types?
+        this._stringText = nextStringText;
+        ReactDOMComponent.BackendIDOperations.updateTextContentByID(
+          this._rootNodeID,
+          nextStringText
+        );
+      }
+    }
+  },
+
+  unmountComponent: function() {
+    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
+  }
+
+});
+
+module.exports = ReactDOMTextComponent;
+
+},{"11":11,"116":116,"27":27,"35":35,"42":42}],52:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMTextarea
+ */
+
+'use strict';
+
+var AutoFocusMixin = _dereq_(2);
+var DOMPropertyOperations = _dereq_(11);
+var LinkedValueUtils = _dereq_(24);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+
+var warning = _dereq_(154);
+
+var textarea = ReactElement.createFactory('textarea');
+
+function forceUpdateIfMounted() {
+  /*jshint validthis:true */
+  if (this.isMounted()) {
+    this.forceUpdate();
+  }
+}
+
+/**
+ * Implements a <textarea> native component that allows setting `value`, and
+ * `defaultValue`. This differs from the traditional DOM API because value is
+ * usually set as PCDATA children.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that affect the
+ * value will trigger updates to the element.
+ *
+ * If `value` is supplied (and not null/undefined), the rendered element will
+ * not trigger updates to the element. Instead, the `value` prop must change in
+ * order for the rendered element to be updated.
+ *
+ * The rendered element will be initialized with an empty value, the prop
+ * `defaultValue` if specified, or the children content (deprecated).
+ */
+var ReactDOMTextarea = ReactClass.createClass({
+  displayName: 'ReactDOMTextarea',
+  tagName: 'TEXTAREA',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  getInitialState: function() {
+    var defaultValue = this.props.defaultValue;
+    // TODO (yungsters): Remove support for children content in <textarea>.
+    var children = this.props.children;
+    if (children != null) {
+      if ("production" !== "development") {
+        ("production" !== "development" ? warning(
+          false,
+          'Use the `defaultValue` or `value` props instead of setting ' +
+          'children on <textarea>.'
+        ) : null);
+      }
+      ("production" !== "development" ? invariant(
+        defaultValue == null,
+        'If you supply `defaultValue` on a <textarea>, do not pass children.'
+      ) : invariant(defaultValue == null));
+      if (Array.isArray(children)) {
+        ("production" !== "development" ? invariant(
+          children.length <= 1,
+          '<textarea> can only have at most one child.'
+        ) : invariant(children.length <= 1));
+        children = children[0];
+      }
+
+      defaultValue = '' + children;
+    }
+    if (defaultValue == null) {
+      defaultValue = '';
+    }
+    var value = LinkedValueUtils.getValue(this);
+    return {
+      // We save the initial value so that `ReactDOMComponent` doesn't update
+      // `textContent` (unnecessary since we update value).
+      // The initial value can be a boolean or object so that's why it's
+      // forced to be a string.
+      initialValue: '' + (value != null ? value : defaultValue)
+    };
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    ("production" !== "development" ? invariant(
+      props.dangerouslySetInnerHTML == null,
+      '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
+    ) : invariant(props.dangerouslySetInnerHTML == null));
+
+    props.defaultValue = null;
+    props.value = null;
+    props.onChange = this._handleChange;
+
+    // Always set children to the same thing. In IE9, the selection range will
+    // get reset if `textContent` is mutated.
+    return textarea(props, this.state.initialValue);
+  },
+
+  componentDidUpdate: function(prevProps, prevState, prevContext) {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      var rootNode = this.getDOMNode();
+      // Cast `value` to a string to ensure the value is set correctly. While
+      // browsers typically do this as necessary, jsdom doesn't.
+      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+    ReactUpdates.asap(forceUpdateIfMounted, this);
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMTextarea;
+
+},{"11":11,"135":135,"154":154,"2":2,"24":24,"27":27,"29":29,"33":33,"57":57,"87":87}],53:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultBatchingStrategy
+ */
+
+'use strict';
+
+var ReactUpdates = _dereq_(87);
+var Transaction = _dereq_(103);
+
+var assign = _dereq_(27);
+var emptyFunction = _dereq_(114);
+
+var RESET_BATCHED_UPDATES = {
+  initialize: emptyFunction,
+  close: function() {
+    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
+  }
+};
+
+var FLUSH_BATCHED_UPDATES = {
+  initialize: emptyFunction,
+  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
+};
+
+var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
+
+function ReactDefaultBatchingStrategyTransaction() {
+  this.reinitializeTransaction();
+}
+
+assign(
+  ReactDefaultBatchingStrategyTransaction.prototype,
+  Transaction.Mixin,
+  {
+    getTransactionWrappers: function() {
+      return TRANSACTION_WRAPPERS;
+    }
+  }
+);
+
+var transaction = new ReactDefaultBatchingStrategyTransaction();
+
+var ReactDefaultBatchingStrategy = {
+  isBatchingUpdates: false,
+
+  /**
+   * Call the provided function in a context within which calls to `setState`
+   * and friends are batched such that components aren't updated unnecessarily.
+   */
+  batchedUpdates: function(callback, a, b, c, d) {
+    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
+
+    ReactDefaultBatchingStrategy.isBatchingUpdates = true;
+
+    // The code is written this way to avoid extra allocations
+    if (alreadyBatchingUpdates) {
+      callback(a, b, c, d);
+    } else {
+      transaction.perform(callback, null, a, b, c, d);
+    }
+  }
+};
+
+module.exports = ReactDefaultBatchingStrategy;
+
+},{"103":103,"114":114,"27":27,"87":87}],54:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultInjection
+ */
+
+'use strict';
+
+var BeforeInputEventPlugin = _dereq_(3);
+var ChangeEventPlugin = _dereq_(7);
+var ClientReactRootIndex = _dereq_(8);
+var DefaultEventPluginOrder = _dereq_(13);
+var EnterLeaveEventPlugin = _dereq_(14);
+var ExecutionEnvironment = _dereq_(21);
+var HTMLDOMPropertyConfig = _dereq_(23);
+var MobileSafariClickEventPlugin = _dereq_(26);
+var ReactBrowserComponentMixin = _dereq_(29);
+var ReactClass = _dereq_(33);
+var ReactComponentBrowserEnvironment =
+  _dereq_(35);
+var ReactDefaultBatchingStrategy = _dereq_(53);
+var ReactDOMComponent = _dereq_(42);
+var ReactDOMButton = _dereq_(41);
+var ReactDOMForm = _dereq_(43);
+var ReactDOMImg = _dereq_(46);
+var ReactDOMIDOperations = _dereq_(44);
+var ReactDOMIframe = _dereq_(45);
+var ReactDOMInput = _dereq_(47);
+var ReactDOMOption = _dereq_(48);
+var ReactDOMSelect = _dereq_(49);
+var ReactDOMTextarea = _dereq_(52);
+var ReactDOMTextComponent = _dereq_(51);
+var ReactElement = _dereq_(57);
+var ReactEventListener = _dereq_(62);
+var ReactInjection = _dereq_(64);
+var ReactInstanceHandles = _dereq_(66);
+var ReactMount = _dereq_(70);
+var ReactReconcileTransaction = _dereq_(80);
+var SelectEventPlugin = _dereq_(89);
+var ServerReactRootIndex = _dereq_(90);
+var SimpleEventPlugin = _dereq_(91);
+var SVGDOMPropertyConfig = _dereq_(88);
+
+var createFullPageComponent = _dereq_(111);
+
+function autoGenerateWrapperClass(type) {
+  return ReactClass.createClass({
+    tagName: type.toUpperCase(),
+    render: function() {
+      return new ReactElement(
+        type,
+        null,
+        null,
+        null,
+        null,
+        this.props
+      );
+    }
+  });
+}
+
+function inject() {
+  ReactInjection.EventEmitter.injectReactEventListener(
+    ReactEventListener
+  );
+
+  /**
+   * Inject modules for resolving DOM hierarchy and plugin ordering.
+   */
+  ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
+  ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
+  ReactInjection.EventPluginHub.injectMount(ReactMount);
+
+  /**
+   * Some important event plugins included by default (without having to require
+   * them).
+   */
+  ReactInjection.EventPluginHub.injectEventPluginsByName({
+    SimpleEventPlugin: SimpleEventPlugin,
+    EnterLeaveEventPlugin: EnterLeaveEventPlugin,
+    ChangeEventPlugin: ChangeEventPlugin,
+    MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
+    SelectEventPlugin: SelectEventPlugin,
+    BeforeInputEventPlugin: BeforeInputEventPlugin
+  });
+
+  ReactInjection.NativeComponent.injectGenericComponentClass(
+    ReactDOMComponent
+  );
+
+  ReactInjection.NativeComponent.injectTextComponentClass(
+    ReactDOMTextComponent
+  );
+
+  ReactInjection.NativeComponent.injectAutoWrapper(
+    autoGenerateWrapperClass
+  );
+
+  // This needs to happen before createFullPageComponent() otherwise the mixin
+  // won't be included.
+  ReactInjection.Class.injectMixin(ReactBrowserComponentMixin);
+
+  ReactInjection.NativeComponent.injectComponentClasses({
+    'button': ReactDOMButton,
+    'form': ReactDOMForm,
+    'iframe': ReactDOMIframe,
+    'img': ReactDOMImg,
+    'input': ReactDOMInput,
+    'option': ReactDOMOption,
+    'select': ReactDOMSelect,
+    'textarea': ReactDOMTextarea,
+
+    'html': createFullPageComponent('html'),
+    'head': createFullPageComponent('head'),
+    'body': createFullPageComponent('body')
+  });
+
+  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
+  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
+
+  ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
+
+  ReactInjection.Updates.injectReconcileTransaction(
+    ReactReconcileTransaction
+  );
+  ReactInjection.Updates.injectBatchingStrategy(
+    ReactDefaultBatchingStrategy
+  );
+
+  ReactInjection.RootIndex.injectCreateReactRootIndex(
+    ExecutionEnvironment.canUseDOM ?
+      ClientReactRootIndex.createReactRootIndex :
+      ServerReactRootIndex.createReactRootIndex
+  );
+
+  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
+  ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
+
+  if ("production" !== "development") {
+    var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
+    if ((/[?&]react_perf\b/).test(url)) {
+      var ReactDefaultPerf = _dereq_(55);
+      ReactDefaultPerf.start();
+    }
+  }
+}
+
+module.exports = {
+  inject: inject
+};
+
+},{"111":111,"13":13,"14":14,"21":21,"23":23,"26":26,"29":29,"3":3,"33":33,"35":35,"41":41,"42":42,"43":43,"44":44,"45":45,"46":46,"47":47,"48":48,"49":49,"51":51,"52":52,"53":53,"55":55,"57":57,"62":62,"64":64,"66":66,"7":7,"70":70,"8":8,"80":80,"88":88,"89":89,"90":90,"91":91}],55:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerf
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+var ReactDefaultPerfAnalysis = _dereq_(56);
+var ReactMount = _dereq_(70);
+var ReactPerf = _dereq_(75);
+
+var performanceNow = _dereq_(146);
+
+function roundFloat(val) {
+  return Math.floor(val * 100) / 100;
+}
+
+function addValue(obj, key, val) {
+  obj[key] = (obj[key] || 0) + val;
+}
+
+var ReactDefaultPerf = {
+  _allMeasurements: [], // last item in the list is the current one
+  _mountStack: [0],
+  _injected: false,
+
+  start: function() {
+    if (!ReactDefaultPerf._injected) {
+      ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
+    }
+
+    ReactDefaultPerf._allMeasurements.length = 0;
+    ReactPerf.enableMeasure = true;
+  },
+
+  stop: function() {
+    ReactPerf.enableMeasure = false;
+  },
+
+  getLastMeasurements: function() {
+    return ReactDefaultPerf._allMeasurements;
+  },
+
+  printExclusive: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
+    console.table(summary.map(function(item) {
+      return {
+        'Component class name': item.componentName,
+        'Total inclusive time (ms)': roundFloat(item.inclusive),
+        'Exclusive mount time (ms)': roundFloat(item.exclusive),
+        'Exclusive render time (ms)': roundFloat(item.render),
+        'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
+        'Render time per instance (ms)': roundFloat(item.render / item.count),
+        'Instances': item.count
+      };
+    }));
+    // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
+    // number.
+  },
+
+  printInclusive: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
+    console.table(summary.map(function(item) {
+      return {
+        'Owner > component': item.componentName,
+        'Inclusive time (ms)': roundFloat(item.time),
+        'Instances': item.count
+      };
+    }));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  getMeasurementsSummaryMap: function(measurements) {
+    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
+      measurements,
+      true
+    );
+    return summary.map(function(item) {
+      return {
+        'Owner > component': item.componentName,
+        'Wasted time (ms)': item.time,
+        'Instances': item.count
+      };
+    });
+  },
+
+  printWasted: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  printDOM: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
+    console.table(summary.map(function(item) {
+      var result = {};
+      result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
+      result['type'] = item.type;
+      result['args'] = JSON.stringify(item.args);
+      return result;
+    }));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  _recordWrite: function(id, fnName, totalTime, args) {
+    // TODO: totalTime isn't that useful since it doesn't count paints/reflows
+    var writes =
+      ReactDefaultPerf
+        ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
+        .writes;
+    writes[id] = writes[id] || [];
+    writes[id].push({
+      type: fnName,
+      time: totalTime,
+      args: args
+    });
+  },
+
+  measure: function(moduleName, fnName, func) {
+    return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+      var totalTime;
+      var rv;
+      var start;
+
+      if (fnName === '_renderNewRootComponent' ||
+          fnName === 'flushBatchedUpdates') {
+        // A "measurement" is a set of metrics recorded for each flush. We want
+        // to group the metrics for a given flush together so we can look at the
+        // components that rendered and the DOM operations that actually
+        // happened to determine the amount of "wasted work" performed.
+        ReactDefaultPerf._allMeasurements.push({
+          exclusive: {},
+          inclusive: {},
+          render: {},
+          counts: {},
+          writes: {},
+          displayNames: {},
+          totalTime: 0
+        });
+        start = performanceNow();
+        rv = func.apply(this, args);
+        ReactDefaultPerf._allMeasurements[
+          ReactDefaultPerf._allMeasurements.length - 1
+        ].totalTime = performanceNow() - start;
+        return rv;
+      } else if (moduleName === 'ReactDOMIDOperations' ||
+        moduleName === 'ReactComponentBrowserEnvironment') {
+        start = performanceNow();
+        rv = func.apply(this, args);
+        totalTime = performanceNow() - start;
+
+        if (fnName === '_mountImageIntoNode') {
+          var mountID = ReactMount.getID(args[1]);
+          ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
+        } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
+          // special format
+          args[0].forEach(function(update) {
+            var writeArgs = {};
+            if (update.fromIndex !== null) {
+              writeArgs.fromIndex = update.fromIndex;
+            }
+            if (update.toIndex !== null) {
+              writeArgs.toIndex = update.toIndex;
+            }
+            if (update.textContent !== null) {
+              writeArgs.textContent = update.textContent;
+            }
+            if (update.markupIndex !== null) {
+              writeArgs.markup = args[1][update.markupIndex];
+            }
+            ReactDefaultPerf._recordWrite(
+              update.parentID,
+              update.type,
+              totalTime,
+              writeArgs
+            );
+          });
+        } else {
+          // basic format
+          ReactDefaultPerf._recordWrite(
+            args[0],
+            fnName,
+            totalTime,
+            Array.prototype.slice.call(args, 1)
+          );
+        }
+        return rv;
+      } else if (moduleName === 'ReactCompositeComponent' && (
+        (// TODO: receiveComponent()?
+        (fnName === 'mountComponent' ||
+        fnName === 'updateComponent' || fnName === '_renderValidatedComponent')))) {
+
+        var rootNodeID = fnName === 'mountComponent' ?
+          args[0] :
+          this._rootNodeID;
+        var isRender = fnName === '_renderValidatedComponent';
+        var isMount = fnName === 'mountComponent';
+
+        var mountStack = ReactDefaultPerf._mountStack;
+        var entry = ReactDefaultPerf._allMeasurements[
+          ReactDefaultPerf._allMeasurements.length - 1
+        ];
+
+        if (isRender) {
+          addValue(entry.counts, rootNodeID, 1);
+        } else if (isMount) {
+          mountStack.push(0);
+        }
+
+        start = performanceNow();
+        rv = func.apply(this, args);
+        totalTime = performanceNow() - start;
+
+        if (isRender) {
+          addValue(entry.render, rootNodeID, totalTime);
+        } else if (isMount) {
+          var subMountTime = mountStack.pop();
+          mountStack[mountStack.length - 1] += totalTime;
+          addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
+          addValue(entry.inclusive, rootNodeID, totalTime);
+        } else {
+          addValue(entry.inclusive, rootNodeID, totalTime);
+        }
+
+        entry.displayNames[rootNodeID] = {
+          current: typeof this._currentElement.type === 'string' ?
+            this._currentElement.type :
+            this.getName(),
+          owner: this._currentElement._owner ?
+            this._currentElement._owner.getName() :
+            '<root>'
+        };
+
+        return rv;
+      } else {
+        return func.apply(this, args);
+      }
+    };
+  }
+};
+
+module.exports = ReactDefaultPerf;
+
+},{"10":10,"146":146,"56":56,"70":70,"75":75}],56:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerfAnalysis
+ */
+
+var assign = _dereq_(27);
+
+// Don't try to save users less than 1.2ms (a number I made up)
+var DONT_CARE_THRESHOLD = 1.2;
+var DOM_OPERATION_TYPES = {
+  '_mountImageIntoNode': 'set innerHTML',
+  INSERT_MARKUP: 'set innerHTML',
+  MOVE_EXISTING: 'move',
+  REMOVE_NODE: 'remove',
+  TEXT_CONTENT: 'set textContent',
+  'updatePropertyByID': 'update attribute',
+  'deletePropertyByID': 'delete attribute',
+  'updateStylesByID': 'update styles',
+  'updateInnerHTMLByID': 'set innerHTML',
+  'dangerouslyReplaceNodeWithMarkupByID': 'replace'
+};
+
+function getTotalTime(measurements) {
+  // TODO: return number of DOM ops? could be misleading.
+  // TODO: measure dropped frames after reconcile?
+  // TODO: log total time of each reconcile and the top-level component
+  // class that triggered it.
+  var totalTime = 0;
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    totalTime += measurement.totalTime;
+  }
+  return totalTime;
+}
+
+function getDOMSummary(measurements) {
+  var items = [];
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var id;
+
+    for (id in measurement.writes) {
+      measurement.writes[id].forEach(function(write) {
+        items.push({
+          id: id,
+          type: DOM_OPERATION_TYPES[write.type] || write.type,
+          args: write.args
+        });
+      });
+    }
+  }
+  return items;
+}
+
+function getExclusiveSummary(measurements) {
+  var candidates = {};
+  var displayName;
+
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var allIDs = assign(
+      {},
+      measurement.exclusive,
+      measurement.inclusive
+    );
+
+    for (var id in allIDs) {
+      displayName = measurement.displayNames[id].current;
+
+      candidates[displayName] = candidates[displayName] || {
+        componentName: displayName,
+        inclusive: 0,
+        exclusive: 0,
+        render: 0,
+        count: 0
+      };
+      if (measurement.render[id]) {
+        candidates[displayName].render += measurement.render[id];
+      }
+      if (measurement.exclusive[id]) {
+        candidates[displayName].exclusive += measurement.exclusive[id];
+      }
+      if (measurement.inclusive[id]) {
+        candidates[displayName].inclusive += measurement.inclusive[id];
+      }
+      if (measurement.counts[id]) {
+        candidates[displayName].count += measurement.counts[id];
+      }
+    }
+  }
+
+  // Now make a sorted array with the results.
+  var arr = [];
+  for (displayName in candidates) {
+    if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
+      arr.push(candidates[displayName]);
+    }
+  }
+
+  arr.sort(function(a, b) {
+    return b.exclusive - a.exclusive;
+  });
+
+  return arr;
+}
+
+function getInclusiveSummary(measurements, onlyClean) {
+  var candidates = {};
+  var inclusiveKey;
+
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var allIDs = assign(
+      {},
+      measurement.exclusive,
+      measurement.inclusive
+    );
+    var cleanComponents;
+
+    if (onlyClean) {
+      cleanComponents = getUnchangedComponents(measurement);
+    }
+
+    for (var id in allIDs) {
+      if (onlyClean && !cleanComponents[id]) {
+        continue;
+      }
+
+      var displayName = measurement.displayNames[id];
+
+      // Inclusive time is not useful for many components without knowing where
+      // they are instantiated. So we aggregate inclusive time with both the
+      // owner and current displayName as the key.
+      inclusiveKey = displayName.owner + ' > ' + displayName.current;
+
+      candidates[inclusiveKey] = candidates[inclusiveKey] || {
+        componentName: inclusiveKey,
+        time: 0,
+        count: 0
+      };
+
+      if (measurement.inclusive[id]) {
+        candidates[inclusiveKey].time += measurement.inclusive[id];
+      }
+      if (measurement.counts[id]) {
+        candidates[inclusiveKey].count += measurement.counts[id];
+      }
+    }
+  }
+
+  // Now make a sorted array with the results.
+  var arr = [];
+  for (inclusiveKey in candidates) {
+    if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
+      arr.push(candidates[inclusiveKey]);
+    }
+  }
+
+  arr.sort(function(a, b) {
+    return b.time - a.time;
+  });
+
+  return arr;
+}
+
+function getUnchangedComponents(measurement) {
+  // For a given reconcile, look at which components did not actually
+  // render anything to the DOM and return a mapping of their ID to
+  // the amount of time it took to render the entire subtree.
+  var cleanComponents = {};
+  var dirtyLeafIDs = Object.keys(measurement.writes);
+  var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
+
+  for (var id in allIDs) {
+    var isDirty = false;
+    // For each component that rendered, see if a component that triggered
+    // a DOM op is in its subtree.
+    for (var i = 0; i < dirtyLeafIDs.length; i++) {
+      if (dirtyLeafIDs[i].indexOf(id) === 0) {
+        isDirty = true;
+        break;
+      }
+    }
+    if (!isDirty && measurement.counts[id] > 0) {
+      cleanComponents[id] = true;
+    }
+  }
+  return cleanComponents;
+}
+
+var ReactDefaultPerfAnalysis = {
+  getExclusiveSummary: getExclusiveSummary,
+  getInclusiveSummary: getInclusiveSummary,
+  getDOMSummary: getDOMSummary,
+  getTotalTime: getTotalTime
+};
+
+module.exports = ReactDefaultPerfAnalysis;
+
+},{"27":27}],57:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElement
+ */
+
+'use strict';
+
+var ReactContext = _dereq_(38);
+var ReactCurrentOwner = _dereq_(39);
+
+var assign = _dereq_(27);
+var warning = _dereq_(154);
+
+var RESERVED_PROPS = {
+  key: true,
+  ref: true
+};
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} object
+ * @param {string} key
+ */
+function defineWarningProperty(object, key) {
+  Object.defineProperty(object, key, {
+
+    configurable: false,
+    enumerable: true,
+
+    get: function() {
+      if (!this._store) {
+        return null;
+      }
+      return this._store[key];
+    },
+
+    set: function(value) {
+      ("production" !== "development" ? warning(
+        false,
+        'Don\'t set the %s property of the React element. Instead, ' +
+        'specify the correct value when initially creating the element.',
+        key
+      ) : null);
+      this._store[key] = value;
+    }
+
+  });
+}
+
+/**
+ * This is updated to true if the membrane is successfully created.
+ */
+var useMutationMembrane = false;
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} element
+ */
+function defineMutationMembrane(prototype) {
+  try {
+    var pseudoFrozenProperties = {
+      props: true
+    };
+    for (var key in pseudoFrozenProperties) {
+      defineWarningProperty(prototype, key);
+    }
+    useMutationMembrane = true;
+  } catch (x) {
+    // IE will fail on defineProperty
+  }
+}
+
+/**
+ * Base constructor for all React elements. This is only used to make this
+ * work with a dynamic instanceof check. Nothing should live on this prototype.
+ *
+ * @param {*} type
+ * @param {string|object} ref
+ * @param {*} key
+ * @param {*} props
+ * @internal
+ */
+var ReactElement = function(type, key, ref, owner, context, props) {
+  // Built-in properties that belong on the element
+  this.type = type;
+  this.key = key;
+  this.ref = ref;
+
+  // Record the component responsible for creating this element.
+  this._owner = owner;
+
+  // TODO: Deprecate withContext, and then the context becomes accessible
+  // through the owner.
+  this._context = context;
+
+  if ("production" !== "development") {
+    // The validation flag and props are currently mutative. We put them on
+    // an external backing store so that we can freeze the whole object.
+    // This can be replaced with a WeakMap once they are implemented in
+    // commonly used development environments.
+    this._store = {props: props, originalProps: assign({}, props)};
+
+    // To make comparing ReactElements easier for testing purposes, we make
+    // the validation flag non-enumerable (where possible, which should
+    // include every environment we run tests in), so the test framework
+    // ignores it.
+    try {
+      Object.defineProperty(this._store, 'validated', {
+        configurable: false,
+        enumerable: false,
+        writable: true
+      });
+    } catch (x) {
+    }
+    this._store.validated = false;
+
+    // We're not allowed to set props directly on the object so we early
+    // return and rely on the prototype membrane to forward to the backing
+    // store.
+    if (useMutationMembrane) {
+      Object.freeze(this);
+      return;
+    }
+  }
+
+  this.props = props;
+};
+
+// We intentionally don't expose the function on the constructor property.
+// ReactElement should be indistinguishable from a plain object.
+ReactElement.prototype = {
+  _isReactElement: true
+};
+
+if ("production" !== "development") {
+  defineMutationMembrane(ReactElement.prototype);
+}
+
+ReactElement.createElement = function(type, config, children) {
+  var propName;
+
+  // Reserved names are extracted
+  var props = {};
+
+  var key = null;
+  var ref = null;
+
+  if (config != null) {
+    ref = config.ref === undefined ? null : config.ref;
+    key = config.key === undefined ? null : '' + config.key;
+    // Remaining properties are added to a new props object
+    for (propName in config) {
+      if (config.hasOwnProperty(propName) &&
+          !RESERVED_PROPS.hasOwnProperty(propName)) {
+        props[propName] = config[propName];
+      }
+    }
+  }
+
+  // Children can be more than one argument, and those are transferred onto
+  // the newly allocated props object.
+  var childrenLength = arguments.length - 2;
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = Array(childrenLength);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 2];
+    }
+    props.children = childArray;
+  }
+
+  // Resolve default props
+  if (type && type.defaultProps) {
+    var defaultProps = type.defaultProps;
+    for (propName in defaultProps) {
+      if (typeof props[propName] === 'undefined') {
+        props[propName] = defaultProps[propName];
+      }
+    }
+  }
+
+  return new ReactElement(
+    type,
+    key,
+    ref,
+    ReactCurrentOwner.current,
+    ReactContext.current,
+    props
+  );
+};
+
+ReactElement.createFactory = function(type) {
+  var factory = ReactElement.createElement.bind(null, type);
+  // Expose the type on the factory and the prototype so that it can be
+  // easily accessed on elements. E.g. <Foo />.type === Foo.type.
+  // This should not be named `constructor` since this may not be the function
+  // that created the element, and it may not even be a constructor.
+  // Legacy hook TODO: Warn if this is accessed
+  factory.type = type;
+  return factory;
+};
+
+ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
+  var newElement = new ReactElement(
+    oldElement.type,
+    oldElement.key,
+    oldElement.ref,
+    oldElement._owner,
+    oldElement._context,
+    newProps
+  );
+
+  if ("production" !== "development") {
+    // If the key on the original is valid, then the clone is valid
+    newElement._store.validated = oldElement._store.validated;
+  }
+  return newElement;
+};
+
+ReactElement.cloneElement = function(element, config, children) {
+  var propName;
+
+  // Original props are copied
+  var props = assign({}, element.props);
+
+  // Reserved names are extracted
+  var key = element.key;
+  var ref = element.ref;
+
+  // Owner will be preserved, unless ref is overridden
+  var owner = element._owner;
+
+  if (config != null) {
+    if (config.ref !== undefined) {
+      // Silently steal the ref from the parent.
+      ref = config.ref;
+      owner = ReactCurrentOwner.current;
+    }
+    if (config.key !== undefined) {
+      key = '' + config.key;
+    }
+    // Remaining properties override existing props
+    for (propName in config) {
+      if (config.hasOwnProperty(propName) &&
+          !RESERVED_PROPS.hasOwnProperty(propName)) {
+        props[propName] = config[propName];
+      }
+    }
+  }
+
+  // Children can be more than one argument, and those are transferred onto
+  // the newly allocated props object.
+  var childrenLength = arguments.length - 2;
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = Array(childrenLength);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 2];
+    }
+    props.children = childArray;
+  }
+
+  return new ReactElement(
+    element.type,
+    key,
+    ref,
+    owner,
+    element._context,
+    props
+  );
+};
+
+/**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid component.
+ * @final
+ */
+ReactElement.isValidElement = function(object) {
+  // ReactTestUtils is often used outside of beforeEach where as React is
+  // within it. This leads to two different instances of React on the same
+  // page. To identify a element from a different React instance we use
+  // a flag instead of an instanceof check.
+  var isElement = !!(object && object._isReactElement);
+  // if (isElement && !(object instanceof ReactElement)) {
+  // This is an indicator that you're using multiple versions of React at the
+  // same time. This will screw with ownership and stuff. Fix it, please.
+  // TODO: We could possibly warn here.
+  // }
+  return isElement;
+};
+
+module.exports = ReactElement;
+
+},{"154":154,"27":27,"38":38,"39":39}],58:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElementValidator
+ */
+
+/**
+ * ReactElementValidator provides a wrapper around a element factory
+ * which validates the props passed to the element. This is intended to be
+ * used only in DEV and could be replaced by a static type checker for languages
+ * that support it.
+ */
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactFragment = _dereq_(63);
+var ReactPropTypeLocations = _dereq_(77);
+var ReactPropTypeLocationNames = _dereq_(76);
+var ReactCurrentOwner = _dereq_(39);
+var ReactNativeComponent = _dereq_(73);
+
+var getIteratorFn = _dereq_(126);
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+function getDeclarationErrorAddendum() {
+  if (ReactCurrentOwner.current) {
+    var name = ReactCurrentOwner.current.getName();
+    if (name) {
+      return ' Check the render method of `' + name + '`.';
+    }
+  }
+  return '';
+}
+
+/**
+ * Warn if there's no key explicitly set on dynamic arrays of children or
+ * object keys are not valid. This allows us to keep track of children between
+ * updates.
+ */
+var ownerHasKeyUseWarning = {};
+
+var loggedTypeFailures = {};
+
+var NUMERIC_PROPERTY_REGEX = /^\d+$/;
+
+/**
+ * Gets the instance's name for use in warnings.
+ *
+ * @internal
+ * @return {?string} Display name or undefined
+ */
+function getName(instance) {
+  var publicInstance = instance && instance.getPublicInstance();
+  if (!publicInstance) {
+    return undefined;
+  }
+  var constructor = publicInstance.constructor;
+  if (!constructor) {
+    return undefined;
+  }
+  return constructor.displayName || constructor.name || undefined;
+}
+
+/**
+ * Gets the current owner's displayName for use in warnings.
+ *
+ * @internal
+ * @return {?string} Display name or undefined
+ */
+function getCurrentOwnerDisplayName() {
+  var current = ReactCurrentOwner.current;
+  return (
+    current && getName(current) || undefined
+  );
+}
+
+/**
+ * Warn if the element doesn't have an explicit key assigned to it.
+ * This element is in an array. The array could grow and shrink or be
+ * reordered. All children that haven't already been validated are required to
+ * have a "key" property assigned to it.
+ *
+ * @internal
+ * @param {ReactElement} element Element that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function validateExplicitKey(element, parentType) {
+  if (element._store.validated || element.key != null) {
+    return;
+  }
+  element._store.validated = true;
+
+  warnAndMonitorForKeyUse(
+    'Each child in an array or iterator should have a unique "key" prop.',
+    element,
+    parentType
+  );
+}
+
+/**
+ * Warn if the key is being defined as an object property but has an incorrect
+ * value.
+ *
+ * @internal
+ * @param {string} name Property name of the key.
+ * @param {ReactElement} element Component that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function validatePropertyKey(name, element, parentType) {
+  if (!NUMERIC_PROPERTY_REGEX.test(name)) {
+    return;
+  }
+  warnAndMonitorForKeyUse(
+    'Child objects should have non-numeric keys so ordering is preserved.',
+    element,
+    parentType
+  );
+}
+
+/**
+ * Shared warning and monitoring code for the key warnings.
+ *
+ * @internal
+ * @param {string} message The base warning that gets output.
+ * @param {ReactElement} element Component that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function warnAndMonitorForKeyUse(message, element, parentType) {
+  var ownerName = getCurrentOwnerDisplayName();
+  var parentName = typeof parentType === 'string' ?
+    parentType : parentType.displayName || parentType.name;
+
+  var useName = ownerName || parentName;
+  var memoizer = ownerHasKeyUseWarning[message] || (
+    (ownerHasKeyUseWarning[message] = {})
+  );
+  if (memoizer.hasOwnProperty(useName)) {
+    return;
+  }
+  memoizer[useName] = true;
+
+  var parentOrOwnerAddendum =
+    ownerName ? (" Check the render method of " + ownerName + ".") :
+    parentName ? (" Check the React.render call using <" + parentName + ">.") :
+    '';
+
+  // Usually the current owner is the offender, but if it accepts children as a
+  // property, it may be the creator of the child that's responsible for
+  // assigning it a key.
+  var childOwnerAddendum = '';
+  if (element &&
+      element._owner &&
+      element._owner !== ReactCurrentOwner.current) {
+    // Name of the component that originally created this child.
+    var childOwnerName = getName(element._owner);
+
+    childOwnerAddendum = (" It was passed a child from " + childOwnerName + ".");
+  }
+
+  ("production" !== "development" ? warning(
+    false,
+    message + '%s%s See http://fb.me/react-warning-keys for more information.',
+    parentOrOwnerAddendum,
+    childOwnerAddendum
+  ) : null);
+}
+
+/**
+ * Ensure that every element either is passed in a static location, in an
+ * array with an explicit keys property defined, or in an object literal
+ * with valid key property.
+ *
+ * @internal
+ * @param {ReactNode} node Statically passed child of any type.
+ * @param {*} parentType node's parent's type.
+ */
+function validateChildKeys(node, parentType) {
+  if (Array.isArray(node)) {
+    for (var i = 0; i < node.length; i++) {
+      var child = node[i];
+      if (ReactElement.isValidElement(child)) {
+        validateExplicitKey(child, parentType);
+      }
+    }
+  } else if (ReactElement.isValidElement(node)) {
+    // This element was passed in a valid location.
+    node._store.validated = true;
+  } else if (node) {
+    var iteratorFn = getIteratorFn(node);
+    // Entry iterators provide implicit keys.
+    if (iteratorFn) {
+      if (iteratorFn !== node.entries) {
+        var iterator = iteratorFn.call(node);
+        var step;
+        while (!(step = iterator.next()).done) {
+          if (ReactElement.isValidElement(step.value)) {
+            validateExplicitKey(step.value, parentType);
+          }
+        }
+      }
+    } else if (typeof node === 'object') {
+      var fragment = ReactFragment.extractIfFragment(node);
+      for (var key in fragment) {
+        if (fragment.hasOwnProperty(key)) {
+          validatePropertyKey(key, fragment[key], parentType);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Assert that the props are valid
+ *
+ * @param {string} componentName Name of the component for error messages.
+ * @param {object} propTypes Map of prop name to a ReactPropType
+ * @param {object} props
+ * @param {string} location e.g. "prop", "context", "child context"
+ * @private
+ */
+function checkPropTypes(componentName, propTypes, props, location) {
+  for (var propName in propTypes) {
+    if (propTypes.hasOwnProperty(propName)) {
+      var error;
+      // Prop type validation may throw. In case they do, we don't want to
+      // fail the render phase where it didn't fail before. So we log it.
+      // After these have been cleaned up, we'll let them throw.
+      try {
+        // This is intentionally an invariant that gets caught. It's the same
+        // behavior as without this statement except with a better message.
+        ("production" !== "development" ? invariant(
+          typeof propTypes[propName] === 'function',
+          '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+          'React.PropTypes.',
+          componentName || 'React class',
+          ReactPropTypeLocationNames[location],
+          propName
+        ) : invariant(typeof propTypes[propName] === 'function'));
+        error = propTypes[propName](props, propName, componentName, location);
+      } catch (ex) {
+        error = ex;
+      }
+      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
+        // Only monitor this failure once because there tends to be a lot of the
+        // same error.
+        loggedTypeFailures[error.message] = true;
+
+        var addendum = getDeclarationErrorAddendum(this);
+        ("production" !== "development" ? warning(false, 'Failed propType: %s%s', error.message, addendum) : null);
+      }
+    }
+  }
+}
+
+var warnedPropsMutations = {};
+
+/**
+ * Warn about mutating props when setting `propName` on `element`.
+ *
+ * @param {string} propName The string key within props that was set
+ * @param {ReactElement} element
+ */
+function warnForPropsMutation(propName, element) {
+  var type = element.type;
+  var elementName = typeof type === 'string' ? type : type.displayName;
+  var ownerName = element._owner ?
+    element._owner.getPublicInstance().constructor.displayName : null;
+
+  var warningKey = propName + '|' + elementName + '|' + ownerName;
+  if (warnedPropsMutations.hasOwnProperty(warningKey)) {
+    return;
+  }
+  warnedPropsMutations[warningKey] = true;
+
+  var elementInfo = '';
+  if (elementName) {
+    elementInfo = ' <' + elementName + ' />';
+  }
+  var ownerInfo = '';
+  if (ownerName) {
+    ownerInfo = ' The element was created by ' + ownerName + '.';
+  }
+
+  ("production" !== "development" ? warning(
+    false,
+    'Don\'t set .props.%s of the React component%s. ' +
+    'Instead, specify the correct value when ' +
+    'initially creating the element.%s',
+    propName,
+    elementInfo,
+    ownerInfo
+  ) : null);
+}
+
+// Inline Object.is polyfill
+function is(a, b) {
+  if (a !== a) {
+    // NaN
+    return b !== b;
+  }
+  if (a === 0 && b === 0) {
+    // +-0
+    return 1 / a === 1 / b;
+  }
+  return a === b;
+}
+
+/**
+ * Given an element, check if its props have been mutated since element
+ * creation (or the last call to this function). In particular, check if any
+ * new props have been added, which we can't directly catch by defining warning
+ * properties on the props object.
+ *
+ * @param {ReactElement} element
+ */
+function checkAndWarnForMutatedProps(element) {
+  if (!element._store) {
+    // Element was created using `new ReactElement` directly or with
+    // `ReactElement.createElement`; skip mutation checking
+    return;
+  }
+
+  var originalProps = element._store.originalProps;
+  var props = element.props;
+
+  for (var propName in props) {
+    if (props.hasOwnProperty(propName)) {
+      if (!originalProps.hasOwnProperty(propName) ||
+          !is(originalProps[propName], props[propName])) {
+        warnForPropsMutation(propName, element);
+
+        // Copy over the new value so that the two props objects match again
+        originalProps[propName] = props[propName];
+      }
+    }
+  }
+}
+
+/**
+ * Given an element, validate that its props follow the propTypes definition,
+ * provided by the type.
+ *
+ * @param {ReactElement} element
+ */
+function validatePropTypes(element) {
+  if (element.type == null) {
+    // This has already warned. Don't throw.
+    return;
+  }
+  // Extract the component class from the element. Converts string types
+  // to a composite class which may have propTypes.
+  // TODO: Validating a string's propTypes is not decoupled from the
+  // rendering target which is problematic.
+  var componentClass = ReactNativeComponent.getComponentClassForElement(
+    element
+  );
+  var name = componentClass.displayName || componentClass.name;
+  if (componentClass.propTypes) {
+    checkPropTypes(
+      name,
+      componentClass.propTypes,
+      element.props,
+      ReactPropTypeLocations.prop
+    );
+  }
+  if (typeof componentClass.getDefaultProps === 'function') {
+    ("production" !== "development" ? warning(
+      componentClass.getDefaultProps.isReactClassApproved,
+      'getDefaultProps is only used on classic React.createClass ' +
+      'definitions. Use a static property named `defaultProps` instead.'
+    ) : null);
+  }
+}
+
+var ReactElementValidator = {
+
+  checkAndWarnForMutatedProps: checkAndWarnForMutatedProps,
+
+  createElement: function(type, props, children) {
+    // We warn in this case but don't throw. We expect the element creation to
+    // succeed and there will likely be errors in render.
+    ("production" !== "development" ? warning(
+      type != null,
+      'React.createElement: type should not be null or undefined. It should ' +
+        'be a string (for DOM elements) or a ReactClass (for composite ' +
+        'components).'
+    ) : null);
+
+    var element = ReactElement.createElement.apply(this, arguments);
+
+    // The result can be nullish if a mock or a custom function is used.
+    // TODO: Drop this when these are no longer allowed as the type argument.
+    if (element == null) {
+      return element;
+    }
+
+    for (var i = 2; i < arguments.length; i++) {
+      validateChildKeys(arguments[i], type);
+    }
+
+    validatePropTypes(element);
+
+    return element;
+  },
+
+  createFactory: function(type) {
+    var validatedFactory = ReactElementValidator.createElement.bind(
+      null,
+      type
+    );
+    // Legacy hook TODO: Warn if this is accessed
+    validatedFactory.type = type;
+
+    if ("production" !== "development") {
+      try {
+        Object.defineProperty(
+          validatedFactory,
+          'type',
+          {
+            enumerable: false,
+            get: function() {
+              ("production" !== "development" ? warning(
+                false,
+                'Factory.type is deprecated. Access the class directly ' +
+                'before passing it to createFactory.'
+              ) : null);
+              Object.defineProperty(this, 'type', {
+                value: type
+              });
+              return type;
+            }
+          }
+        );
+      } catch (x) {
+        // IE will fail on defineProperty (es5-shim/sham too)
+      }
+    }
+
+
+    return validatedFactory;
+  },
+
+  cloneElement: function(element, props, children) {
+    var newElement = ReactElement.cloneElement.apply(this, arguments);
+    for (var i = 2; i < arguments.length; i++) {
+      validateChildKeys(arguments[i], newElement.type);
+    }
+    validatePropTypes(newElement);
+    return newElement;
+  }
+
+};
+
+module.exports = ReactElementValidator;
+
+},{"126":126,"135":135,"154":154,"39":39,"57":57,"63":63,"73":73,"76":76,"77":77}],59:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEmptyComponent
+ */
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactInstanceMap = _dereq_(67);
+
+var invariant = _dereq_(135);
+
+var component;
+// This registry keeps track of the React IDs of the components that rendered to
+// `null` (in reality a placeholder such as `noscript`)
+var nullComponentIDsRegistry = {};
+
+var ReactEmptyComponentInjection = {
+  injectEmptyComponent: function(emptyComponent) {
+    component = ReactElement.createFactory(emptyComponent);
+  }
+};
+
+var ReactEmptyComponentType = function() {};
+ReactEmptyComponentType.prototype.componentDidMount = function() {
+  var internalInstance = ReactInstanceMap.get(this);
+  // TODO: Make sure we run these methods in the correct order, we shouldn't
+  // need this check. We're going to assume if we're here it means we ran
+  // componentWillUnmount already so there is no internal instance (it gets
+  // removed as part of the unmounting process).
+  if (!internalInstance) {
+    return;
+  }
+  registerNullComponentID(internalInstance._rootNodeID);
+};
+ReactEmptyComponentType.prototype.componentWillUnmount = function() {
+  var internalInstance = ReactInstanceMap.get(this);
+  // TODO: Get rid of this check. See TODO in componentDidMount.
+  if (!internalInstance) {
+    return;
+  }
+  deregisterNullComponentID(internalInstance._rootNodeID);
+};
+ReactEmptyComponentType.prototype.render = function() {
+  ("production" !== "development" ? invariant(
+    component,
+    'Trying to return null from a render, but no null placeholder component ' +
+    'was injected.'
+  ) : invariant(component));
+  return component();
+};
+
+var emptyElement = ReactElement.createElement(ReactEmptyComponentType);
+
+/**
+ * Mark the component as having rendered to null.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function registerNullComponentID(id) {
+  nullComponentIDsRegistry[id] = true;
+}
+
+/**
+ * Unmark the component as having rendered to null: it renders to something now.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function deregisterNullComponentID(id) {
+  delete nullComponentIDsRegistry[id];
+}
+
+/**
+ * @param {string} id Component's `_rootNodeID`.
+ * @return {boolean} True if the component is rendered to null.
+ */
+function isNullComponentID(id) {
+  return !!nullComponentIDsRegistry[id];
+}
+
+var ReactEmptyComponent = {
+  emptyElement: emptyElement,
+  injection: ReactEmptyComponentInjection,
+  isNullComponentID: isNullComponentID
+};
+
+module.exports = ReactEmptyComponent;
+
+},{"135":135,"57":57,"67":67}],60:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactErrorUtils
+ * @typechecks
+ */
+
+"use strict";
+
+var ReactErrorUtils = {
+  /**
+   * Creates a guarded version of a function. This is supposed to make debugging
+   * of event handlers easier. To aid debugging with the browser's debugger,
+   * this currently simply returns the original function.
+   *
+   * @param {function} func Function to be executed
+   * @param {string} name The name of the guard
+   * @return {function}
+   */
+  guard: function(func, name) {
+    return func;
+  }
+};
+
+module.exports = ReactErrorUtils;
+
+},{}],61:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventEmitterMixin
+ */
+
+'use strict';
+
+var EventPluginHub = _dereq_(17);
+
+function runEventQueueInBatch(events) {
+  EventPluginHub.enqueueEvents(events);
+  EventPluginHub.processEventQueue();
+}
+
+var ReactEventEmitterMixin = {
+
+  /**
+   * Streams a fired top-level event to `EventPluginHub` where plugins have the
+   * opportunity to create `ReactEvent`s to be dispatched.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {object} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native environment event.
+   */
+  handleTopLevel: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var events = EventPluginHub.extractEvents(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent
+    );
+
+    runEventQueueInBatch(events);
+  }
+};
+
+module.exports = ReactEventEmitterMixin;
+
+},{"17":17}],62:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventListener
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventListener = _dereq_(16);
+var ExecutionEnvironment = _dereq_(21);
+var PooledClass = _dereq_(28);
+var ReactInstanceHandles = _dereq_(66);
+var ReactMount = _dereq_(70);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+var getEventTarget = _dereq_(125);
+var getUnboundedScrollPosition = _dereq_(131);
+
+/**
+ * Finds the parent React component of `node`.
+ *
+ * @param {*} node
+ * @return {?DOMEventTarget} Parent container, or `null` if the specified node
+ *                           is not nested.
+ */
+function findParent(node) {
+  // TODO: It may be a good idea to cache this to prevent unnecessary DOM
+  // traversal, but caching is difficult to do correctly without using a
+  // mutation observer to listen for all DOM changes.
+  var nodeID = ReactMount.getID(node);
+  var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
+  var container = ReactMount.findReactContainerForID(rootID);
+  var parent = ReactMount.getFirstReactDOM(container);
+  return parent;
+}
+
+// Used to store ancestor hierarchy in top level callback
+function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
+  this.topLevelType = topLevelType;
+  this.nativeEvent = nativeEvent;
+  this.ancestors = [];
+}
+assign(TopLevelCallbackBookKeeping.prototype, {
+  destructor: function() {
+    this.topLevelType = null;
+    this.nativeEvent = null;
+    this.ancestors.length = 0;
+  }
+});
+PooledClass.addPoolingTo(
+  TopLevelCallbackBookKeeping,
+  PooledClass.twoArgumentPooler
+);
+
+function handleTopLevelImpl(bookKeeping) {
+  var topLevelTarget = ReactMount.getFirstReactDOM(
+    getEventTarget(bookKeeping.nativeEvent)
+  ) || window;
+
+  // Loop through the hierarchy, in case there's any nested components.
+  // It's important that we build the array of ancestors before calling any
+  // event handlers, because event handlers can modify the DOM, leading to
+  // inconsistencies with ReactMount's node cache. See #1105.
+  var ancestor = topLevelTarget;
+  while (ancestor) {
+    bookKeeping.ancestors.push(ancestor);
+    ancestor = findParent(ancestor);
+  }
+
+  for (var i = 0, l = bookKeeping.ancestors.length; i < l; i++) {
+    topLevelTarget = bookKeeping.ancestors[i];
+    var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
+    ReactEventListener._handleTopLevel(
+      bookKeeping.topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      bookKeeping.nativeEvent
+    );
+  }
+}
+
+function scrollValueMonitor(cb) {
+  var scrollPosition = getUnboundedScrollPosition(window);
+  cb(scrollPosition);
+}
+
+var ReactEventListener = {
+  _enabled: true,
+  _handleTopLevel: null,
+
+  WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,
+
+  setHandleTopLevel: function(handleTopLevel) {
+    ReactEventListener._handleTopLevel = handleTopLevel;
+  },
+
+  setEnabled: function(enabled) {
+    ReactEventListener._enabled = !!enabled;
+  },
+
+  isEnabled: function() {
+    return ReactEventListener._enabled;
+  },
+
+
+  /**
+   * Traps top-level events by using event bubbling.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {string} handlerBaseName Event name (e.g. "click").
+   * @param {object} handle Element on which to attach listener.
+   * @return {object} An object with a remove function which will forcefully
+   *                  remove the listener.
+   * @internal
+   */
+  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+    var element = handle;
+    if (!element) {
+      return null;
+    }
+    return EventListener.listen(
+      element,
+      handlerBaseName,
+      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+    );
+  },
+
+  /**
+   * Traps a top-level event by using event capturing.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {string} handlerBaseName Event name (e.g. "click").
+   * @param {object} handle Element on which to attach listener.
+   * @return {object} An object with a remove function which will forcefully
+   *                  remove the listener.
+   * @internal
+   */
+  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+    var element = handle;
+    if (!element) {
+      return null;
+    }
+    return EventListener.capture(
+      element,
+      handlerBaseName,
+      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+    );
+  },
+
+  monitorScrollValue: function(refresh) {
+    var callback = scrollValueMonitor.bind(null, refresh);
+    EventListener.listen(window, 'scroll', callback);
+  },
+
+  dispatchEvent: function(topLevelType, nativeEvent) {
+    if (!ReactEventListener._enabled) {
+      return;
+    }
+
+    var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
+      topLevelType,
+      nativeEvent
+    );
+    try {
+      // Event queue being processed in the same cycle allows
+      // `preventDefault`.
+      ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
+    } finally {
+      TopLevelCallbackBookKeeping.release(bookKeeping);
+    }
+  }
+};
+
+module.exports = ReactEventListener;
+
+},{"125":125,"131":131,"16":16,"21":21,"27":27,"28":28,"66":66,"70":70,"87":87}],63:[function(_dereq_,module,exports){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+* @providesModule ReactFragment
+*/
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+
+var warning = _dereq_(154);
+
+/**
+ * We used to allow keyed objects to serve as a collection of ReactElements,
+ * or nested sets. This allowed us a way to explicitly key a set a fragment of
+ * components. This is now being replaced with an opaque data structure.
+ * The upgrade path is to call React.addons.createFragment({ key: value }) to
+ * create a keyed fragment. The resulting data structure is opaque, for now.
+ */
+
+if ("production" !== "development") {
+  var fragmentKey = '_reactFragment';
+  var didWarnKey = '_reactDidWarn';
+  var canWarnForReactFragment = false;
+
+  try {
+    // Feature test. Don't even try to issue this warning if we can't use
+    // enumerable: false.
+
+    var dummy = function() {
+      return 1;
+    };
+
+    Object.defineProperty(
+      {},
+      fragmentKey,
+      {enumerable: false, value: true}
+    );
+
+    Object.defineProperty(
+      {},
+      'key',
+      {enumerable: true, get: dummy}
+    );
+
+    canWarnForReactFragment = true;
+  } catch (x) { }
+
+  var proxyPropertyAccessWithWarning = function(obj, key) {
+    Object.defineProperty(obj, key, {
+      enumerable: true,
+      get: function() {
+        ("production" !== "development" ? warning(
+          this[didWarnKey],
+          'A ReactFragment is an opaque type. Accessing any of its ' +
+          'properties is deprecated. Pass it to one of the React.Children ' +
+          'helpers.'
+        ) : null);
+        this[didWarnKey] = true;
+        return this[fragmentKey][key];
+      },
+      set: function(value) {
+        ("production" !== "development" ? warning(
+          this[didWarnKey],
+          'A ReactFragment is an immutable opaque type. Mutating its ' +
+          'properties is deprecated.'
+        ) : null);
+        this[didWarnKey] = true;
+        this[fragmentKey][key] = value;
+      }
+    });
+  };
+
+  var issuedWarnings = {};
+
+  var didWarnForFragment = function(fragment) {
+    // We use the keys and the type of the value as a heuristic to dedupe the
+    // warning to avoid spamming too much.
+    var fragmentCacheKey = '';
+    for (var key in fragment) {
+      fragmentCacheKey += key + ':' + (typeof fragment[key]) + ',';
+    }
+    var alreadyWarnedOnce = !!issuedWarnings[fragmentCacheKey];
+    issuedWarnings[fragmentCacheKey] = true;
+    return alreadyWarnedOnce;
+  };
+}
+
+var ReactFragment = {
+  // Wrap a keyed object in an opaque proxy that warns you if you access any
+  // of its properties.
+  create: function(object) {
+    if ("production" !== "development") {
+      if (typeof object !== 'object' || !object || Array.isArray(object)) {
+        ("production" !== "development" ? warning(
+          false,
+          'React.addons.createFragment only accepts a single object.',
+          object
+        ) : null);
+        return object;
+      }
+      if (ReactElement.isValidElement(object)) {
+        ("production" !== "development" ? warning(
+          false,
+          'React.addons.createFragment does not accept a ReactElement ' +
+          'without a wrapper object.'
+        ) : null);
+        return object;
+      }
+      if (canWarnForReactFragment) {
+        var proxy = {};
+        Object.defineProperty(proxy, fragmentKey, {
+          enumerable: false,
+          value: object
+        });
+        Object.defineProperty(proxy, didWarnKey, {
+          writable: true,
+          enumerable: false,
+          value: false
+        });
+        for (var key in object) {
+          proxyPropertyAccessWithWarning(proxy, key);
+        }
+        Object.preventExtensions(proxy);
+        return proxy;
+      }
+    }
+    return object;
+  },
+  // Extract the original keyed object from the fragment opaque type. Warn if
+  // a plain object is passed here.
+  extract: function(fragment) {
+    if ("production" !== "development") {
+      if (canWarnForReactFragment) {
+        if (!fragment[fragmentKey]) {
+          ("production" !== "development" ? warning(
+            didWarnForFragment(fragment),
+            'Any use of a keyed object should be wrapped in ' +
+            'React.addons.createFragment(object) before being passed as a ' +
+            'child.'
+          ) : null);
+          return fragment;
+        }
+        return fragment[fragmentKey];
+      }
+    }
+    return fragment;
+  },
+  // Check if this is a fragment and if so, extract the keyed object. If it
+  // is a fragment-like object, warn that it should be wrapped. Ignore if we
+  // can't determine what kind of object this is.
+  extractIfFragment: function(fragment) {
+    if ("production" !== "development") {
+      if (canWarnForReactFragment) {
+        // If it is the opaque type, return the keyed object.
+        if (fragment[fragmentKey]) {
+          return fragment[fragmentKey];
+        }
+        // Otherwise, check each property if it has an element, if it does
+        // it is probably meant as a fragment, so we can warn early. Defer,
+        // the warning to extract.
+        for (var key in fragment) {
+          if (fragment.hasOwnProperty(key) &&
+              ReactElement.isValidElement(fragment[key])) {
+            // This looks like a fragment object, we should provide an
+            // early warning.
+            return ReactFragment.extract(fragment);
+          }
+        }
+      }
+    }
+    return fragment;
+  }
+};
+
+module.exports = ReactFragment;
+
+},{"154":154,"57":57}],64:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInjection
+ */
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+var EventPluginHub = _dereq_(17);
+var ReactComponentEnvironment = _dereq_(36);
+var ReactClass = _dereq_(33);
+var ReactEmptyComponent = _dereq_(59);
+var ReactBrowserEventEmitter = _dereq_(30);
+var ReactNativeComponent = _dereq_(73);
+var ReactDOMComponent = _dereq_(42);
+var ReactPerf = _dereq_(75);
+var ReactRootIndex = _dereq_(83);
+var ReactUpdates = _dereq_(87);
+
+var ReactInjection = {
+  Component: ReactComponentEnvironment.injection,
+  Class: ReactClass.injection,
+  DOMComponent: ReactDOMComponent.injection,
+  DOMProperty: DOMProperty.injection,
+  EmptyComponent: ReactEmptyComponent.injection,
+  EventPluginHub: EventPluginHub.injection,
+  EventEmitter: ReactBrowserEventEmitter.injection,
+  NativeComponent: ReactNativeComponent.injection,
+  Perf: ReactPerf.injection,
+  RootIndex: ReactRootIndex.injection,
+  Updates: ReactUpdates.injection
+};
+
+module.exports = ReactInjection;
+
+},{"10":10,"17":17,"30":30,"33":33,"36":36,"42":42,"59":59,"73":73,"75":75,"83":83,"87":87}],65:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInputSelection
+ */
+
+'use strict';
+
+var ReactDOMSelection = _dereq_(50);
+
+var containsNode = _dereq_(109);
+var focusNode = _dereq_(119);
+var getActiveElement = _dereq_(121);
+
+function isInDocument(node) {
+  return containsNode(document.documentElement, node);
+}
+
+/**
+ * @ReactInputSelection: React input selection module. Based on Selection.js,
+ * but modified to be suitable for react and has a couple of bug fixes (doesn't
+ * assume buttons have range selections allowed).
+ * Input selection module for React.
+ */
+var ReactInputSelection = {
+
+  hasSelectionCapabilities: function(elem) {
+    return elem && (
+      ((elem.nodeName === 'INPUT' && elem.type === 'text') ||
+      elem.nodeName === 'TEXTAREA' || elem.contentEditable === 'true')
+    );
+  },
+
+  getSelectionInformation: function() {
+    var focusedElem = getActiveElement();
+    return {
+      focusedElem: focusedElem,
+      selectionRange:
+          ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
+          ReactInputSelection.getSelection(focusedElem) :
+          null
+    };
+  },
+
+  /**
+   * @restoreSelection: If any selection information was potentially lost,
+   * restore it. This is useful when performing operations that could remove dom
+   * nodes and place them back in, resulting in focus being lost.
+   */
+  restoreSelection: function(priorSelectionInformation) {
+    var curFocusedElem = getActiveElement();
+    var priorFocusedElem = priorSelectionInformation.focusedElem;
+    var priorSelectionRange = priorSelectionInformation.selectionRange;
+    if (curFocusedElem !== priorFocusedElem &&
+        isInDocument(priorFocusedElem)) {
+      if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
+        ReactInputSelection.setSelection(
+          priorFocusedElem,
+          priorSelectionRange
+        );
+      }
+      focusNode(priorFocusedElem);
+    }
+  },
+
+  /**
+   * @getSelection: Gets the selection bounds of a focused textarea, input or
+   * contentEditable node.
+   * - at input: Look up selection bounds of this input
+   * - at return {start: selectionStart, end: selectionEnd}
+   */
+  getSelection: function(input) {
+    var selection;
+
+    if ('selectionStart' in input) {
+      // Modern browser with input or textarea.
+      selection = {
+        start: input.selectionStart,
+        end: input.selectionEnd
+      };
+    } else if (document.selection && input.nodeName === 'INPUT') {
+      // IE8 input.
+      var range = document.selection.createRange();
+      // There can only be one selection per document in IE, so it must
+      // be in our element.
+      if (range.parentElement() === input) {
+        selection = {
+          start: -range.moveStart('character', -input.value.length),
+          end: -range.moveEnd('character', -input.value.length)
+        };
+      }
+    } else {
+      // Content editable or old IE textarea.
+      selection = ReactDOMSelection.getOffsets(input);
+    }
+
+    return selection || {start: 0, end: 0};
+  },
+
+  /**
+   * @setSelection: Sets the selection bounds of a textarea or input and focuses
+   * the input.
+   * - at input     Set selection bounds of this input or textarea
+   * - at offsets   Object of same form that is returned from get*
+   */
+  setSelection: function(input, offsets) {
+    var start = offsets.start;
+    var end = offsets.end;
+    if (typeof end === 'undefined') {
+      end = start;
+    }
+
+    if ('selectionStart' in input) {
+      input.selectionStart = start;
+      input.selectionEnd = Math.min(end, input.value.length);
+    } else if (document.selection && input.nodeName === 'INPUT') {
+      var range = input.createTextRange();
+      range.collapse(true);
+      range.moveStart('character', start);
+      range.moveEnd('character', end - start);
+      range.select();
+    } else {
+      ReactDOMSelection.setOffsets(input, offsets);
+    }
+  }
+};
+
+module.exports = ReactInputSelection;
+
+},{"109":109,"119":119,"121":121,"50":50}],66:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInstanceHandles
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactRootIndex = _dereq_(83);
+
+var invariant = _dereq_(135);
+
+var SEPARATOR = '.';
+var SEPARATOR_LENGTH = SEPARATOR.length;
+
+/**
+ * Maximum depth of traversals before we consider the possibility of a bad ID.
+ */
+var MAX_TREE_DEPTH = 100;
+
+/**
+ * Creates a DOM ID prefix to use when mounting React components.
+ *
+ * @param {number} index A unique integer
+ * @return {string} React root ID.
+ * @internal
+ */
+function getReactRootIDString(index) {
+  return SEPARATOR + index.toString(36);
+}
+
+/**
+ * Checks if a character in the supplied ID is a separator or the end.
+ *
+ * @param {string} id A React DOM ID.
+ * @param {number} index Index of the character to check.
+ * @return {boolean} True if the character is a separator or end of the ID.
+ * @private
+ */
+function isBoundary(id, index) {
+  return id.charAt(index) === SEPARATOR || index === id.length;
+}
+
+/**
+ * Checks if the supplied string is a valid React DOM ID.
+ *
+ * @param {string} id A React DOM ID, maybe.
+ * @return {boolean} True if the string is a valid React DOM ID.
+ * @private
+ */
+function isValidID(id) {
+  return id === '' || (
+    id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
+  );
+}
+
+/**
+ * Checks if the first ID is an ancestor of or equal to the second ID.
+ *
+ * @param {string} ancestorID
+ * @param {string} descendantID
+ * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
+ * @internal
+ */
+function isAncestorIDOf(ancestorID, descendantID) {
+  return (
+    descendantID.indexOf(ancestorID) === 0 &&
+    isBoundary(descendantID, ancestorID.length)
+  );
+}
+
+/**
+ * Gets the parent ID of the supplied React DOM ID, `id`.
+ *
+ * @param {string} id ID of a component.
+ * @return {string} ID of the parent, or an empty string.
+ * @private
+ */
+function getParentID(id) {
+  return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
+}
+
+/**
+ * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
+ * supplied `destinationID`. If they are equal, the ID is returned.
+ *
+ * @param {string} ancestorID ID of an ancestor node of `destinationID`.
+ * @param {string} destinationID ID of the destination node.
+ * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
+ * @private
+ */
+function getNextDescendantID(ancestorID, destinationID) {
+  ("production" !== "development" ? invariant(
+    isValidID(ancestorID) && isValidID(destinationID),
+    'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
+    ancestorID,
+    destinationID
+  ) : invariant(isValidID(ancestorID) && isValidID(destinationID)));
+  ("production" !== "development" ? invariant(
+    isAncestorIDOf(ancestorID, destinationID),
+    'getNextDescendantID(...): React has made an invalid assumption about ' +
+    'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
+    ancestorID,
+    destinationID
+  ) : invariant(isAncestorIDOf(ancestorID, destinationID)));
+  if (ancestorID === destinationID) {
+    return ancestorID;
+  }
+  // Skip over the ancestor and the immediate separator. Traverse until we hit
+  // another separator or we reach the end of `destinationID`.
+  var start = ancestorID.length + SEPARATOR_LENGTH;
+  var i;
+  for (i = start; i < destinationID.length; i++) {
+    if (isBoundary(destinationID, i)) {
+      break;
+    }
+  }
+  return destinationID.substr(0, i);
+}
+
+/**
+ * Gets the nearest common ancestor ID of two IDs.
+ *
+ * Using this ID scheme, the nearest common ancestor ID is the longest common
+ * prefix of the two IDs that immediately preceded a "marker" in both strings.
+ *
+ * @param {string} oneID
+ * @param {string} twoID
+ * @return {string} Nearest common ancestor ID, or the empty string if none.
+ * @private
+ */
+function getFirstCommonAncestorID(oneID, twoID) {
+  var minLength = Math.min(oneID.length, twoID.length);
+  if (minLength === 0) {
+    return '';
+  }
+  var lastCommonMarkerIndex = 0;
+  // Use `<=` to traverse until the "EOL" of the shorter string.
+  for (var i = 0; i <= minLength; i++) {
+    if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
+      lastCommonMarkerIndex = i;
+    } else if (oneID.charAt(i) !== twoID.charAt(i)) {
+      break;
+    }
+  }
+  var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
+  ("production" !== "development" ? invariant(
+    isValidID(longestCommonID),
+    'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
+    oneID,
+    twoID,
+    longestCommonID
+  ) : invariant(isValidID(longestCommonID)));
+  return longestCommonID;
+}
+
+/**
+ * Traverses the parent path between two IDs (either up or down). The IDs must
+ * not be the same, and there must exist a parent path between them. If the
+ * callback returns `false`, traversal is stopped.
+ *
+ * @param {?string} start ID at which to start traversal.
+ * @param {?string} stop ID at which to end traversal.
+ * @param {function} cb Callback to invoke each ID with.
+ * @param {?boolean} skipFirst Whether or not to skip the first node.
+ * @param {?boolean} skipLast Whether or not to skip the last node.
+ * @private
+ */
+function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
+  start = start || '';
+  stop = stop || '';
+  ("production" !== "development" ? invariant(
+    start !== stop,
+    'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
+    start
+  ) : invariant(start !== stop));
+  var traverseUp = isAncestorIDOf(stop, start);
+  ("production" !== "development" ? invariant(
+    traverseUp || isAncestorIDOf(start, stop),
+    'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
+    'not have a parent path.',
+    start,
+    stop
+  ) : invariant(traverseUp || isAncestorIDOf(start, stop)));
+  // Traverse from `start` to `stop` one depth at a time.
+  var depth = 0;
+  var traverse = traverseUp ? getParentID : getNextDescendantID;
+  for (var id = start; /* until break */; id = traverse(id, stop)) {
+    var ret;
+    if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
+      ret = cb(id, traverseUp, arg);
+    }
+    if (ret === false || id === stop) {
+      // Only break //after// visiting `stop`.
+      break;
+    }
+    ("production" !== "development" ? invariant(
+      depth++ < MAX_TREE_DEPTH,
+      'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
+      'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
+      start, stop
+    ) : invariant(depth++ < MAX_TREE_DEPTH));
+  }
+}
+
+/**
+ * Manages the IDs assigned to DOM representations of React components. This
+ * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
+ * order to simulate events).
+ *
+ * @internal
+ */
+var ReactInstanceHandles = {
+
+  /**
+   * Constructs a React root ID
+   * @return {string} A React root ID.
+   */
+  createReactRootID: function() {
+    return getReactRootIDString(ReactRootIndex.createReactRootIndex());
+  },
+
+  /**
+   * Constructs a React ID by joining a root ID with a name.
+   *
+   * @param {string} rootID Root ID of a parent component.
+   * @param {string} name A component's name (as flattened children).
+   * @return {string} A React ID.
+   * @internal
+   */
+  createReactID: function(rootID, name) {
+    return rootID + name;
+  },
+
+  /**
+   * Gets the DOM ID of the React component that is the root of the tree that
+   * contains the React component with the supplied DOM ID.
+   *
+   * @param {string} id DOM ID of a React component.
+   * @return {?string} DOM ID of the React component that is the root.
+   * @internal
+   */
+  getReactRootIDFromNodeID: function(id) {
+    if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
+      var index = id.indexOf(SEPARATOR, 1);
+      return index > -1 ? id.substr(0, index) : id;
+    }
+    return null;
+  },
+
+  /**
+   * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
+   * should would receive a `mouseEnter` or `mouseLeave` event.
+   *
+   * NOTE: Does not invoke the callback on the nearest common ancestor because
+   * nothing "entered" or "left" that element.
+   *
+   * @param {string} leaveID ID being left.
+   * @param {string} enterID ID being entered.
+   * @param {function} cb Callback to invoke on each entered/left ID.
+   * @param {*} upArg Argument to invoke the callback with on left IDs.
+   * @param {*} downArg Argument to invoke the callback with on entered IDs.
+   * @internal
+   */
+  traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
+    var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
+    if (ancestorID !== leaveID) {
+      traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
+    }
+    if (ancestorID !== enterID) {
+      traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
+    }
+  },
+
+  /**
+   * Simulates the traversal of a two-phase, capture/bubble event dispatch.
+   *
+   * NOTE: This traversal happens on IDs without touching the DOM.
+   *
+   * @param {string} targetID ID of the target node.
+   * @param {function} cb Callback to invoke.
+   * @param {*} arg Argument to invoke the callback with.
+   * @internal
+   */
+  traverseTwoPhase: function(targetID, cb, arg) {
+    if (targetID) {
+      traverseParentPath('', targetID, cb, arg, true, false);
+      traverseParentPath(targetID, '', cb, arg, false, true);
+    }
+  },
+
+  /**
+   * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
+   * example, passing `.0.$row-0.1` would result in `cb` getting called
+   * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
+   *
+   * NOTE: This traversal happens on IDs without touching the DOM.
+   *
+   * @param {string} targetID ID of the target node.
+   * @param {function} cb Callback to invoke.
+   * @param {*} arg Argument to invoke the callback with.
+   * @internal
+   */
+  traverseAncestors: function(targetID, cb, arg) {
+    traverseParentPath('', targetID, cb, arg, true, false);
+  },
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _getFirstCommonAncestorID: getFirstCommonAncestorID,
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _getNextDescendantID: getNextDescendantID,
+
+  isAncestorIDOf: isAncestorIDOf,
+
+  SEPARATOR: SEPARATOR
+
+};
+
+module.exports = ReactInstanceHandles;
+
+},{"135":135,"83":83}],67:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInstanceMap
+ */
+
+'use strict';
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ */
+
+// TODO: Replace this with ES6: var ReactInstanceMap = new Map();
+var ReactInstanceMap = {
+
+  /**
+   * This API should be called `delete` but we'd have to make sure to always
+   * transform these to strings for IE support. When this transform is fully
+   * supported we can rename it.
+   */
+  remove: function(key) {
+    key._reactInternalInstance = undefined;
+  },
+
+  get: function(key) {
+    return key._reactInternalInstance;
+  },
+
+  has: function(key) {
+    return key._reactInternalInstance !== undefined;
+  },
+
+  set: function(key, value) {
+    key._reactInternalInstance = value;
+  }
+
+};
+
+module.exports = ReactInstanceMap;
+
+},{}],68:[function(_dereq_,module,exports){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactLifeCycle
+ */
+
+'use strict';
+
+/**
+ * This module manages the bookkeeping when a component is in the process
+ * of being mounted or being unmounted. This is used as a way to enforce
+ * invariants (or warnings) when it is not recommended to call
+ * setState/forceUpdate.
+ *
+ * currentlyMountingInstance: During the construction phase, it is not possible
+ * to trigger an update since the instance is not fully mounted yet. However, we
+ * currently allow this as a convenience for mutating the initial state.
+ *
+ * currentlyUnmountingInstance: During the unmounting phase, the instance is
+ * still mounted and can therefore schedule an update. However, this is not
+ * recommended and probably an error since it's about to be unmounted.
+ * Therefore we still want to trigger in an error for that case.
+ */
+
+var ReactLifeCycle = {
+  currentlyMountingInstance: null,
+  currentlyUnmountingInstance: null
+};
+
+module.exports = ReactLifeCycle;
+
+},{}],69:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMarkupChecksum
+ */
+
+'use strict';
+
+var adler32 = _dereq_(106);
+
+var ReactMarkupChecksum = {
+  CHECKSUM_ATTR_NAME: 'data-react-checksum',
+
+  /**
+   * @param {string} markup Markup string
+   * @return {string} Markup string with checksum attribute attached
+   */
+  addChecksumToMarkup: function(markup) {
+    var checksum = adler32(markup);
+    return markup.replace(
+      '>',
+      ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
+    );
+  },
+
+  /**
+   * @param {string} markup to use
+   * @param {DOMElement} element root React element
+   * @returns {boolean} whether or not the markup is the same
+   */
+  canReuseMarkup: function(markup, element) {
+    var existingChecksum = element.getAttribute(
+      ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+    );
+    existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
+    var markupChecksum = adler32(markup);
+    return markupChecksum === existingChecksum;
+  }
+};
+
+module.exports = ReactMarkupChecksum;
+
+},{"106":106}],70:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMount
+ */
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+var ReactBrowserEventEmitter = _dereq_(30);
+var ReactCurrentOwner = _dereq_(39);
+var ReactElement = _dereq_(57);
+var ReactElementValidator = _dereq_(58);
+var ReactEmptyComponent = _dereq_(59);
+var ReactInstanceHandles = _dereq_(66);
+var ReactInstanceMap = _dereq_(67);
+var ReactMarkupChecksum = _dereq_(69);
+var ReactPerf = _dereq_(75);
+var ReactReconciler = _dereq_(81);
+var ReactUpdateQueue = _dereq_(86);
+var ReactUpdates = _dereq_(87);
+
+var emptyObject = _dereq_(115);
+var containsNode = _dereq_(109);
+var getReactRootElementInContainer = _dereq_(129);
+var instantiateReactComponent = _dereq_(134);
+var invariant = _dereq_(135);
+var setInnerHTML = _dereq_(148);
+var shouldUpdateReactComponent = _dereq_(151);
+var warning = _dereq_(154);
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+
+var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
+var nodeCache = {};
+
+var ELEMENT_NODE_TYPE = 1;
+var DOC_NODE_TYPE = 9;
+
+/** Mapping from reactRootID to React component instance. */
+var instancesByReactRootID = {};
+
+/** Mapping from reactRootID to `container` nodes. */
+var containersByReactRootID = {};
+
+if ("production" !== "development") {
+  /** __DEV__-only mapping from reactRootID to root elements. */
+  var rootElementsByReactRootID = {};
+}
+
+// Used to store breadth-first search state in findComponentRoot.
+var findComponentRootReusableArray = [];
+
+/**
+ * Finds the index of the first character
+ * that's not common between the two given strings.
+ *
+ * @return {number} the index of the character where the strings diverge
+ */
+function firstDifferenceIndex(string1, string2) {
+  var minLen = Math.min(string1.length, string2.length);
+  for (var i = 0; i < minLen; i++) {
+    if (string1.charAt(i) !== string2.charAt(i)) {
+      return i;
+    }
+  }
+  return string1.length === string2.length ? -1 : minLen;
+}
+
+/**
+ * @param {DOMElement} container DOM element that may contain a React component.
+ * @return {?string} A "reactRoot" ID, if a React component is rendered.
+ */
+function getReactRootID(container) {
+  var rootElement = getReactRootElementInContainer(container);
+  return rootElement && ReactMount.getID(rootElement);
+}
+
+/**
+ * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
+ * element can return its control whose name or ID equals ATTR_NAME. All
+ * DOM nodes support `getAttributeNode` but this can also get called on
+ * other objects so just return '' if we're given something other than a
+ * DOM node (such as window).
+ *
+ * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
+ * @return {string} ID of the supplied `domNode`.
+ */
+function getID(node) {
+  var id = internalGetID(node);
+  if (id) {
+    if (nodeCache.hasOwnProperty(id)) {
+      var cached = nodeCache[id];
+      if (cached !== node) {
+        ("production" !== "development" ? invariant(
+          !isValid(cached, id),
+          'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
+          ATTR_NAME, id
+        ) : invariant(!isValid(cached, id)));
+
+        nodeCache[id] = node;
+      }
+    } else {
+      nodeCache[id] = node;
+    }
+  }
+
+  return id;
+}
+
+function internalGetID(node) {
+  // If node is something like a window, document, or text node, none of
+  // which support attributes or a .getAttribute method, gracefully return
+  // the empty string, as if the attribute were missing.
+  return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
+}
+
+/**
+ * Sets the React-specific ID of the given node.
+ *
+ * @param {DOMElement} node The DOM node whose ID will be set.
+ * @param {string} id The value of the ID attribute.
+ */
+function setID(node, id) {
+  var oldID = internalGetID(node);
+  if (oldID !== id) {
+    delete nodeCache[oldID];
+  }
+  node.setAttribute(ATTR_NAME, id);
+  nodeCache[id] = node;
+}
+
+/**
+ * Finds the node with the supplied React-generated DOM ID.
+ *
+ * @param {string} id A React-generated DOM ID.
+ * @return {DOMElement} DOM node with the suppled `id`.
+ * @internal
+ */
+function getNode(id) {
+  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
+    nodeCache[id] = ReactMount.findReactNodeByID(id);
+  }
+  return nodeCache[id];
+}
+
+/**
+ * Finds the node with the supplied public React instance.
+ *
+ * @param {*} instance A public React instance.
+ * @return {?DOMElement} DOM node with the suppled `id`.
+ * @internal
+ */
+function getNodeFromInstance(instance) {
+  var id = ReactInstanceMap.get(instance)._rootNodeID;
+  if (ReactEmptyComponent.isNullComponentID(id)) {
+    return null;
+  }
+  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
+    nodeCache[id] = ReactMount.findReactNodeByID(id);
+  }
+  return nodeCache[id];
+}
+
+/**
+ * A node is "valid" if it is contained by a currently mounted container.
+ *
+ * This means that the node does not have to be contained by a document in
+ * order to be considered valid.
+ *
+ * @param {?DOMElement} node The candidate DOM node.
+ * @param {string} id The expected ID of the node.
+ * @return {boolean} Whether the node is contained by a mounted container.
+ */
+function isValid(node, id) {
+  if (node) {
+    ("production" !== "development" ? invariant(
+      internalGetID(node) === id,
+      'ReactMount: Unexpected modification of `%s`',
+      ATTR_NAME
+    ) : invariant(internalGetID(node) === id));
+
+    var container = ReactMount.findReactContainerForID(id);
+    if (container && containsNode(container, node)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Causes the cache to forget about one React-specific ID.
+ *
+ * @param {string} id The ID to forget.
+ */
+function purgeID(id) {
+  delete nodeCache[id];
+}
+
+var deepestNodeSoFar = null;
+function findDeepestCachedAncestorImpl(ancestorID) {
+  var ancestor = nodeCache[ancestorID];
+  if (ancestor && isValid(ancestor, ancestorID)) {
+    deepestNodeSoFar = ancestor;
+  } else {
+    // This node isn't populated in the cache, so presumably none of its
+    // descendants are. Break out of the loop.
+    return false;
+  }
+}
+
+/**
+ * Return the deepest cached node whose ID is a prefix of `targetID`.
+ */
+function findDeepestCachedAncestor(targetID) {
+  deepestNodeSoFar = null;
+  ReactInstanceHandles.traverseAncestors(
+    targetID,
+    findDeepestCachedAncestorImpl
+  );
+
+  var foundNode = deepestNodeSoFar;
+  deepestNodeSoFar = null;
+  return foundNode;
+}
+
+/**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {ReactReconcileTransaction} transaction
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ */
+function mountComponentIntoNode(
+    componentInstance,
+    rootID,
+    container,
+    transaction,
+    shouldReuseMarkup) {
+  var markup = ReactReconciler.mountComponent(
+    componentInstance, rootID, transaction, emptyObject
+  );
+  componentInstance._isTopLevel = true;
+  ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup);
+}
+
+/**
+ * Batched mount.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ */
+function batchedMountComponentIntoNode(
+    componentInstance,
+    rootID,
+    container,
+    shouldReuseMarkup) {
+  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+  transaction.perform(
+    mountComponentIntoNode,
+    null,
+    componentInstance,
+    rootID,
+    container,
+    transaction,
+    shouldReuseMarkup
+  );
+  ReactUpdates.ReactReconcileTransaction.release(transaction);
+}
+
+/**
+ * Mounting is the process of initializing a React component by creating its
+ * representative DOM elements and inserting them into a supplied `container`.
+ * Any prior content inside `container` is destroyed in the process.
+ *
+ *   ReactMount.render(
+ *     component,
+ *     document.getElementById('container')
+ *   );
+ *
+ *   <div id="container">                   <-- Supplied `container`.
+ *     <div data-reactid=".3">              <-- Rendered reactRoot of React
+ *       // ...                                 component.
+ *     </div>
+ *   </div>
+ *
+ * Inside of `container`, the first element rendered is the "reactRoot".
+ */
+var ReactMount = {
+  /** Exposed for debugging purposes **/
+  _instancesByReactRootID: instancesByReactRootID,
+
+  /**
+   * This is a hook provided to support rendering React components while
+   * ensuring that the apparent scroll position of its `container` does not
+   * change.
+   *
+   * @param {DOMElement} container The `container` being rendered into.
+   * @param {function} renderCallback This must be called once to do the render.
+   */
+  scrollMonitor: function(container, renderCallback) {
+    renderCallback();
+  },
+
+  /**
+   * Take a component that's already mounted into the DOM and replace its props
+   * @param {ReactComponent} prevComponent component instance already in the DOM
+   * @param {ReactElement} nextElement component instance to render
+   * @param {DOMElement} container container to render into
+   * @param {?function} callback function triggered on completion
+   */
+  _updateRootComponent: function(
+      prevComponent,
+      nextElement,
+      container,
+      callback) {
+    if ("production" !== "development") {
+      ReactElementValidator.checkAndWarnForMutatedProps(nextElement);
+    }
+
+    ReactMount.scrollMonitor(container, function() {
+      ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement);
+      if (callback) {
+        ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
+      }
+    });
+
+    if ("production" !== "development") {
+      // Record the root element in case it later gets transplanted.
+      rootElementsByReactRootID[getReactRootID(container)] =
+        getReactRootElementInContainer(container);
+    }
+
+    return prevComponent;
+  },
+
+  /**
+   * Register a component into the instance map and starts scroll value
+   * monitoring
+   * @param {ReactComponent} nextComponent component instance to render
+   * @param {DOMElement} container container to render into
+   * @return {string} reactRoot ID prefix
+   */
+  _registerComponent: function(nextComponent, container) {
+    ("production" !== "development" ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      '_registerComponent(...): Target container is not a DOM element.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    ReactBrowserEventEmitter.ensureScrollValueMonitoring();
+
+    var reactRootID = ReactMount.registerContainer(container);
+    instancesByReactRootID[reactRootID] = nextComponent;
+    return reactRootID;
+  },
+
+  /**
+   * Render a new component into the DOM.
+   * @param {ReactElement} nextElement element to render
+   * @param {DOMElement} container container to render into
+   * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
+   * @return {ReactComponent} nextComponent
+   */
+  _renderNewRootComponent: function(
+    nextElement,
+    container,
+    shouldReuseMarkup
+  ) {
+    // Various parts of our code (such as ReactCompositeComponent's
+    // _renderValidatedComponent) assume that calls to render aren't nested;
+    // verify that that's the case.
+    ("production" !== "development" ? warning(
+      ReactCurrentOwner.current == null,
+      '_renderNewRootComponent(): Render methods should be a pure function ' +
+      'of props and state; triggering nested component updates from ' +
+      'render is not allowed. If necessary, trigger nested updates in ' +
+      'componentDidUpdate.'
+    ) : null);
+
+    var componentInstance = instantiateReactComponent(nextElement, null);
+    var reactRootID = ReactMount._registerComponent(
+      componentInstance,
+      container
+    );
+
+    // The initial render is synchronous but any updates that happen during
+    // rendering, in componentWillMount or componentDidMount, will be batched
+    // according to the current batching strategy.
+
+    ReactUpdates.batchedUpdates(
+      batchedMountComponentIntoNode,
+      componentInstance,
+      reactRootID,
+      container,
+      shouldReuseMarkup
+    );
+
+    if ("production" !== "development") {
+      // Record the root element in case it later gets transplanted.
+      rootElementsByReactRootID[reactRootID] =
+        getReactRootElementInContainer(container);
+    }
+
+    return componentInstance;
+  },
+
+  /**
+   * Renders a React component into the DOM in the supplied `container`.
+   *
+   * If the React component was previously rendered into `container`, this will
+   * perform an update on it and only mutate the DOM as necessary to reflect the
+   * latest React component.
+   *
+   * @param {ReactElement} nextElement Component element to render.
+   * @param {DOMElement} container DOM element to render into.
+   * @param {?function} callback function triggered on completion
+   * @return {ReactComponent} Component instance rendered in `container`.
+   */
+  render: function(nextElement, container, callback) {
+    ("production" !== "development" ? invariant(
+      ReactElement.isValidElement(nextElement),
+      'React.render(): Invalid component element.%s',
+      (
+        typeof nextElement === 'string' ?
+          ' Instead of passing an element string, make sure to instantiate ' +
+          'it by passing it to React.createElement.' :
+        typeof nextElement === 'function' ?
+          ' Instead of passing a component class, make sure to instantiate ' +
+          'it by passing it to React.createElement.' :
+        // Check if it quacks like an element
+        nextElement != null && nextElement.props !== undefined ?
+          ' This may be caused by unintentionally loading two independent ' +
+          'copies of React.' :
+          ''
+      )
+    ) : invariant(ReactElement.isValidElement(nextElement)));
+
+    var prevComponent = instancesByReactRootID[getReactRootID(container)];
+
+    if (prevComponent) {
+      var prevElement = prevComponent._currentElement;
+      if (shouldUpdateReactComponent(prevElement, nextElement)) {
+        return ReactMount._updateRootComponent(
+          prevComponent,
+          nextElement,
+          container,
+          callback
+        ).getPublicInstance();
+      } else {
+        ReactMount.unmountComponentAtNode(container);
+      }
+    }
+
+    var reactRootElement = getReactRootElementInContainer(container);
+    var containerHasReactMarkup =
+      reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
+
+    if ("production" !== "development") {
+      if (!containerHasReactMarkup || reactRootElement.nextSibling) {
+        var rootElementSibling = reactRootElement;
+        while (rootElementSibling) {
+          if (ReactMount.isRenderedByReact(rootElementSibling)) {
+            ("production" !== "development" ? warning(
+              false,
+              'render(): Target node has markup rendered by React, but there ' +
+              'are unrelated nodes as well. This is most commonly caused by ' +
+              'white-space inserted around server-rendered markup.'
+            ) : null);
+            break;
+          }
+
+          rootElementSibling = rootElementSibling.nextSibling;
+        }
+      }
+    }
+
+    var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
+
+    var component = ReactMount._renderNewRootComponent(
+      nextElement,
+      container,
+      shouldReuseMarkup
+    ).getPublicInstance();
+    if (callback) {
+      callback.call(component);
+    }
+    return component;
+  },
+
+  /**
+   * Constructs a component instance of `constructor` with `initialProps` and
+   * renders it into the supplied `container`.
+   *
+   * @param {function} constructor React component constructor.
+   * @param {?object} props Initial props of the component instance.
+   * @param {DOMElement} container DOM element to render into.
+   * @return {ReactComponent} Component instance rendered in `container`.
+   */
+  constructAndRenderComponent: function(constructor, props, container) {
+    var element = ReactElement.createElement(constructor, props);
+    return ReactMount.render(element, container);
+  },
+
+  /**
+   * Constructs a component instance of `constructor` with `initialProps` and
+   * renders it into a container node identified by supplied `id`.
+   *
+   * @param {function} componentConstructor React component constructor
+   * @param {?object} props Initial props of the component instance.
+   * @param {string} id ID of the DOM element to render into.
+   * @return {ReactComponent} Component instance rendered in the container node.
+   */
+  constructAndRenderComponentByID: function(constructor, props, id) {
+    var domNode = document.getElementById(id);
+    ("production" !== "development" ? invariant(
+      domNode,
+      'Tried to get element with id of "%s" but it is not present on the page.',
+      id
+    ) : invariant(domNode));
+    return ReactMount.constructAndRenderComponent(constructor, props, domNode);
+  },
+
+  /**
+   * Registers a container node into which React components will be rendered.
+   * This also creates the "reactRoot" ID that will be assigned to the element
+   * rendered within.
+   *
+   * @param {DOMElement} container DOM element to register as a container.
+   * @return {string} The "reactRoot" ID of elements rendered within.
+   */
+  registerContainer: function(container) {
+    var reactRootID = getReactRootID(container);
+    if (reactRootID) {
+      // If one exists, make sure it is a valid "reactRoot" ID.
+      reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
+    }
+    if (!reactRootID) {
+      // No valid "reactRoot" ID found, create one.
+      reactRootID = ReactInstanceHandles.createReactRootID();
+    }
+    containersByReactRootID[reactRootID] = container;
+    return reactRootID;
+  },
+
+  /**
+   * Unmounts and destroys the React component rendered in the `container`.
+   *
+   * @param {DOMElement} container DOM element containing a React component.
+   * @return {boolean} True if a component was found in and unmounted from
+   *                   `container`
+   */
+  unmountComponentAtNode: function(container) {
+    // Various parts of our code (such as ReactCompositeComponent's
+    // _renderValidatedComponent) assume that calls to render aren't nested;
+    // verify that that's the case. (Strictly speaking, unmounting won't cause a
+    // render but we still don't expect to be in a render call here.)
+    ("production" !== "development" ? warning(
+      ReactCurrentOwner.current == null,
+      'unmountComponentAtNode(): Render methods should be a pure function of ' +
+      'props and state; triggering nested component updates from render is ' +
+      'not allowed. If necessary, trigger nested updates in ' +
+      'componentDidUpdate.'
+    ) : null);
+
+    ("production" !== "development" ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      'unmountComponentAtNode(...): Target container is not a DOM element.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    var reactRootID = getReactRootID(container);
+    var component = instancesByReactRootID[reactRootID];
+    if (!component) {
+      return false;
+    }
+    ReactMount.unmountComponentFromNode(component, container);
+    delete instancesByReactRootID[reactRootID];
+    delete containersByReactRootID[reactRootID];
+    if ("production" !== "development") {
+      delete rootElementsByReactRootID[reactRootID];
+    }
+    return true;
+  },
+
+  /**
+   * Unmounts a component and removes it from the DOM.
+   *
+   * @param {ReactComponent} instance React component instance.
+   * @param {DOMElement} container DOM element to unmount from.
+   * @final
+   * @internal
+   * @see {ReactMount.unmountComponentAtNode}
+   */
+  unmountComponentFromNode: function(instance, container) {
+    ReactReconciler.unmountComponent(instance);
+
+    if (container.nodeType === DOC_NODE_TYPE) {
+      container = container.documentElement;
+    }
+
+    // http://jsperf.com/emptying-a-node
+    while (container.lastChild) {
+      container.removeChild(container.lastChild);
+    }
+  },
+
+  /**
+   * Finds the container DOM element that contains React component to which the
+   * supplied DOM `id` belongs.
+   *
+   * @param {string} id The ID of an element rendered by a React component.
+   * @return {?DOMElement} DOM element that contains the `id`.
+   */
+  findReactContainerForID: function(id) {
+    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
+    var container = containersByReactRootID[reactRootID];
+
+    if ("production" !== "development") {
+      var rootElement = rootElementsByReactRootID[reactRootID];
+      if (rootElement && rootElement.parentNode !== container) {
+        ("production" !== "development" ? invariant(
+          // Call internalGetID here because getID calls isValid which calls
+          // findReactContainerForID (this function).
+          internalGetID(rootElement) === reactRootID,
+          'ReactMount: Root element ID differed from reactRootID.'
+        ) : invariant(// Call internalGetID here because getID calls isValid which calls
+        // findReactContainerForID (this function).
+        internalGetID(rootElement) === reactRootID));
+
+        var containerChild = container.firstChild;
+        if (containerChild &&
+            reactRootID === internalGetID(containerChild)) {
+          // If the container has a new child with the same ID as the old
+          // root element, then rootElementsByReactRootID[reactRootID] is
+          // just stale and needs to be updated. The case that deserves a
+          // warning is when the container is empty.
+          rootElementsByReactRootID[reactRootID] = containerChild;
+        } else {
+          ("production" !== "development" ? warning(
+            false,
+            'ReactMount: Root element has been removed from its original ' +
+            'container. New container:', rootElement.parentNode
+          ) : null);
+        }
+      }
+    }
+
+    return container;
+  },
+
+  /**
+   * Finds an element rendered by React with the supplied ID.
+   *
+   * @param {string} id ID of a DOM node in the React component.
+   * @return {DOMElement} Root DOM node of the React component.
+   */
+  findReactNodeByID: function(id) {
+    var reactRoot = ReactMount.findReactContainerForID(id);
+    return ReactMount.findComponentRoot(reactRoot, id);
+  },
+
+  /**
+   * True if the supplied `node` is rendered by React.
+   *
+   * @param {*} node DOM Element to check.
+   * @return {boolean} True if the DOM Element appears to be rendered by React.
+   * @internal
+   */
+  isRenderedByReact: function(node) {
+    if (node.nodeType !== 1) {
+      // Not a DOMElement, therefore not a React component
+      return false;
+    }
+    var id = ReactMount.getID(node);
+    return id ? id.charAt(0) === SEPARATOR : false;
+  },
+
+  /**
+   * Traverses up the ancestors of the supplied node to find a node that is a
+   * DOM representation of a React component.
+   *
+   * @param {*} node
+   * @return {?DOMEventTarget}
+   * @internal
+   */
+  getFirstReactDOM: function(node) {
+    var current = node;
+    while (current && current.parentNode !== current) {
+      if (ReactMount.isRenderedByReact(current)) {
+        return current;
+      }
+      current = current.parentNode;
+    }
+    return null;
+  },
+
+  /**
+   * Finds a node with the supplied `targetID` inside of the supplied
+   * `ancestorNode`.  Exploits the ID naming scheme to perform the search
+   * quickly.
+   *
+   * @param {DOMEventTarget} ancestorNode Search from this root.
+   * @pararm {string} targetID ID of the DOM representation of the component.
+   * @return {DOMEventTarget} DOM node with the supplied `targetID`.
+   * @internal
+   */
+  findComponentRoot: function(ancestorNode, targetID) {
+    var firstChildren = findComponentRootReusableArray;
+    var childIndex = 0;
+
+    var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
+
+    firstChildren[0] = deepestAncestor.firstChild;
+    firstChildren.length = 1;
+
+    while (childIndex < firstChildren.length) {
+      var child = firstChildren[childIndex++];
+      var targetChild;
+
+      while (child) {
+        var childID = ReactMount.getID(child);
+        if (childID) {
+          // Even if we find the node we're looking for, we finish looping
+          // through its siblings to ensure they're cached so that we don't have
+          // to revisit this node again. Otherwise, we make n^2 calls to getID
+          // when visiting the many children of a single node in order.
+
+          if (targetID === childID) {
+            targetChild = child;
+          } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
+            // If we find a child whose ID is an ancestor of the given ID,
+            // then we can be sure that we only want to search the subtree
+            // rooted at this child, so we can throw out the rest of the
+            // search state.
+            firstChildren.length = childIndex = 0;
+            firstChildren.push(child.firstChild);
+          }
+
+        } else {
+          // If this child had no ID, then there's a chance that it was
+          // injected automatically by the browser, as when a `<table>`
+          // element sprouts an extra `<tbody>` child as a side effect of
+          // `.innerHTML` parsing. Optimistically continue down this
+          // branch, but not before examining the other siblings.
+          firstChildren.push(child.firstChild);
+        }
+
+        child = child.nextSibling;
+      }
+
+      if (targetChild) {
+        // Emptying firstChildren/findComponentRootReusableArray is
+        // not necessary for correctness, but it helps the GC reclaim
+        // any nodes that were left at the end of the search.
+        firstChildren.length = 0;
+
+        return targetChild;
+      }
+    }
+
+    firstChildren.length = 0;
+
+    ("production" !== "development" ? invariant(
+      false,
+      'findComponentRoot(..., %s): Unable to find element. This probably ' +
+      'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
+      'usually due to forgetting a <tbody> when using tables, nesting tags ' +
+      'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
+      'parent. ' +
+      'Try inspecting the child nodes of the element with React ID `%s`.',
+      targetID,
+      ReactMount.getID(ancestorNode)
+    ) : invariant(false));
+  },
+
+  _mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
+    ("production" !== "development" ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      'mountComponentIntoNode(...): Target container is not valid.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    if (shouldReuseMarkup) {
+      var rootElement = getReactRootElementInContainer(container);
+      if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) {
+        return;
+      } else {
+        var checksum = rootElement.getAttribute(
+          ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+        );
+        rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
+
+        var rootMarkup = rootElement.outerHTML;
+        rootElement.setAttribute(
+          ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
+          checksum
+        );
+
+        var diffIndex = firstDifferenceIndex(markup, rootMarkup);
+        var difference = ' (client) ' +
+          markup.substring(diffIndex - 20, diffIndex + 20) +
+          '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20);
+
+        ("production" !== "development" ? invariant(
+          container.nodeType !== DOC_NODE_TYPE,
+          'You\'re trying to render a component to the document using ' +
+          'server rendering but the checksum was invalid. This usually ' +
+          'means you rendered a different component type or props on ' +
+          'the client from the one on the server, or your render() ' +
+          'methods are impure. React cannot handle this case due to ' +
+          'cross-browser quirks by rendering at the document root. You ' +
+          'should look for environment dependent code in your components ' +
+          'and ensure the props are the same client and server side:\n%s',
+          difference
+        ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+        if ("production" !== "development") {
+          ("production" !== "development" ? warning(
+            false,
+            'React attempted to reuse markup in a container but the ' +
+            'checksum was invalid. This generally means that you are ' +
+            'using server rendering and the markup generated on the ' +
+            'server was not what the client was expecting. React injected ' +
+            'new markup to compensate which works but you have lost many ' +
+            'of the benefits of server rendering. Instead, figure out ' +
+            'why the markup being generated is different on the client ' +
+            'or server:\n%s',
+            difference
+          ) : null);
+        }
+      }
+    }
+
+    ("production" !== "development" ? invariant(
+      container.nodeType !== DOC_NODE_TYPE,
+      'You\'re trying to render a component to the document but ' +
+        'you didn\'t use server rendering. We can\'t do this ' +
+        'without using server rendering due to cross-browser quirks. ' +
+        'See React.renderToString() for server rendering.'
+    ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+    setInnerHTML(container, markup);
+  },
+
+  /**
+   * React ID utilities.
+   */
+
+  getReactRootID: getReactRootID,
+
+  getID: getID,
+
+  setID: setID,
+
+  getNode: getNode,
+
+  getNodeFromInstance: getNodeFromInstance,
+
+  purgeID: purgeID
+};
+
+ReactPerf.measureMethods(ReactMount, 'ReactMount', {
+  _renderNewRootComponent: '_renderNewRootComponent',
+  _mountImageIntoNode: '_mountImageIntoNode'
+});
+
+module.exports = ReactMount;
+
+},{"10":10,"109":109,"115":115,"129":129,"134":134,"135":135,"148":148,"151":151,"154":154,"30":30,"39":39,"57":57,"58":58,"59":59,"66":66,"67":67,"69":69,"75":75,"81":81,"86":86,"87":87}],71:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChild
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactComponentEnvironment = _dereq_(36);
+var ReactMultiChildUpdateTypes = _dereq_(72);
+
+var ReactReconciler = _dereq_(81);
+var ReactChildReconciler = _dereq_(31);
+
+/**
+ * Updating children of a component may trigger recursive updates. The depth is
+ * used to batch recursive updates to render markup more efficiently.
+ *
+ * @type {number}
+ * @private
+ */
+var updateDepth = 0;
+
+/**
+ * Queue of update configuration objects.
+ *
+ * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
+ *
+ * @type {array<object>}
+ * @private
+ */
+var updateQueue = [];
+
+/**
+ * Queue of markup to be rendered.
+ *
+ * @type {array<string>}
+ * @private
+ */
+var markupQueue = [];
+
+/**
+ * Enqueues markup to be rendered and inserted at a supplied index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} markup Markup that renders into an element.
+ * @param {number} toIndex Destination index.
+ * @private
+ */
+function enqueueMarkup(parentID, markup, toIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
+    markupIndex: markupQueue.push(markup) - 1,
+    textContent: null,
+    fromIndex: null,
+    toIndex: toIndex
+  });
+}
+
+/**
+ * Enqueues moving an existing element to another index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Source index of the existing element.
+ * @param {number} toIndex Destination index of the element.
+ * @private
+ */
+function enqueueMove(parentID, fromIndex, toIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
+    markupIndex: null,
+    textContent: null,
+    fromIndex: fromIndex,
+    toIndex: toIndex
+  });
+}
+
+/**
+ * Enqueues removing an element at an index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Index of the element to remove.
+ * @private
+ */
+function enqueueRemove(parentID, fromIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.REMOVE_NODE,
+    markupIndex: null,
+    textContent: null,
+    fromIndex: fromIndex,
+    toIndex: null
+  });
+}
+
+/**
+ * Enqueues setting the text content.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} textContent Text content to set.
+ * @private
+ */
+function enqueueTextContent(parentID, textContent) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
+    markupIndex: null,
+    textContent: textContent,
+    fromIndex: null,
+    toIndex: null
+  });
+}
+
+/**
+ * Processes any enqueued updates.
+ *
+ * @private
+ */
+function processQueue() {
+  if (updateQueue.length) {
+    ReactComponentEnvironment.processChildrenUpdates(
+      updateQueue,
+      markupQueue
+    );
+    clearQueue();
+  }
+}
+
+/**
+ * Clears any enqueued updates.
+ *
+ * @private
+ */
+function clearQueue() {
+  updateQueue.length = 0;
+  markupQueue.length = 0;
+}
+
+/**
+ * ReactMultiChild are capable of reconciling multiple children.
+ *
+ * @class ReactMultiChild
+ * @internal
+ */
+var ReactMultiChild = {
+
+  /**
+   * Provides common functionality for components that must reconcile multiple
+   * children. This is used by `ReactDOMComponent` to mount, update, and
+   * unmount child components.
+   *
+   * @lends {ReactMultiChild.prototype}
+   */
+  Mixin: {
+
+    /**
+     * Generates a "mount image" for each of the supplied children. In the case
+     * of `ReactDOMComponent`, a mount image is a string of markup.
+     *
+     * @param {?object} nestedChildren Nested child maps.
+     * @return {array} An array of mounted representations.
+     * @internal
+     */
+    mountChildren: function(nestedChildren, transaction, context) {
+      var children = ReactChildReconciler.instantiateChildren(
+        nestedChildren, transaction, context
+      );
+      this._renderedChildren = children;
+      var mountImages = [];
+      var index = 0;
+      for (var name in children) {
+        if (children.hasOwnProperty(name)) {
+          var child = children[name];
+          // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+          var rootID = this._rootNodeID + name;
+          var mountImage = ReactReconciler.mountComponent(
+            child,
+            rootID,
+            transaction,
+            context
+          );
+          child._mountIndex = index;
+          mountImages.push(mountImage);
+          index++;
+        }
+      }
+      return mountImages;
+    },
+
+    /**
+     * Replaces any rendered children with a text content string.
+     *
+     * @param {string} nextContent String of content.
+     * @internal
+     */
+    updateTextContent: function(nextContent) {
+      updateDepth++;
+      var errorThrown = true;
+      try {
+        var prevChildren = this._renderedChildren;
+        // Remove any rendered children.
+        ReactChildReconciler.unmountChildren(prevChildren);
+        // TODO: The setTextContent operation should be enough
+        for (var name in prevChildren) {
+          if (prevChildren.hasOwnProperty(name)) {
+            this._unmountChildByName(prevChildren[name], name);
+          }
+        }
+        // Set new text content.
+        this.setTextContent(nextContent);
+        errorThrown = false;
+      } finally {
+        updateDepth--;
+        if (!updateDepth) {
+          if (errorThrown) {
+            clearQueue();
+          } else {
+            processQueue();
+          }
+        }
+      }
+    },
+
+    /**
+     * Updates the rendered children with new children.
+     *
+     * @param {?object} nextNestedChildren Nested child maps.
+     * @param {ReactReconcileTransaction} transaction
+     * @internal
+     */
+    updateChildren: function(nextNestedChildren, transaction, context) {
+      updateDepth++;
+      var errorThrown = true;
+      try {
+        this._updateChildren(nextNestedChildren, transaction, context);
+        errorThrown = false;
+      } finally {
+        updateDepth--;
+        if (!updateDepth) {
+          if (errorThrown) {
+            clearQueue();
+          } else {
+            processQueue();
+          }
+        }
+
+      }
+    },
+
+    /**
+     * Improve performance by isolating this hot code path from the try/catch
+     * block in `updateChildren`.
+     *
+     * @param {?object} nextNestedChildren Nested child maps.
+     * @param {ReactReconcileTransaction} transaction
+     * @final
+     * @protected
+     */
+    _updateChildren: function(nextNestedChildren, transaction, context) {
+      var prevChildren = this._renderedChildren;
+      var nextChildren = ReactChildReconciler.updateChildren(
+        prevChildren, nextNestedChildren, transaction, context
+      );
+      this._renderedChildren = nextChildren;
+      if (!nextChildren && !prevChildren) {
+        return;
+      }
+      var name;
+      // `nextIndex` will increment for each child in `nextChildren`, but
+      // `lastIndex` will be the last index visited in `prevChildren`.
+      var lastIndex = 0;
+      var nextIndex = 0;
+      for (name in nextChildren) {
+        if (!nextChildren.hasOwnProperty(name)) {
+          continue;
+        }
+        var prevChild = prevChildren && prevChildren[name];
+        var nextChild = nextChildren[name];
+        if (prevChild === nextChild) {
+          this.moveChild(prevChild, nextIndex, lastIndex);
+          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+          prevChild._mountIndex = nextIndex;
+        } else {
+          if (prevChild) {
+            // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
+            lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+            this._unmountChildByName(prevChild, name);
+          }
+          // The child must be instantiated before it's mounted.
+          this._mountChildByNameAtIndex(
+            nextChild, name, nextIndex, transaction, context
+          );
+        }
+        nextIndex++;
+      }
+      // Remove children that are no longer present.
+      for (name in prevChildren) {
+        if (prevChildren.hasOwnProperty(name) &&
+            !(nextChildren && nextChildren.hasOwnProperty(name))) {
+          this._unmountChildByName(prevChildren[name], name);
+        }
+      }
+    },
+
+    /**
+     * Unmounts all rendered children. This should be used to clean up children
+     * when this component is unmounted.
+     *
+     * @internal
+     */
+    unmountChildren: function() {
+      var renderedChildren = this._renderedChildren;
+      ReactChildReconciler.unmountChildren(renderedChildren);
+      this._renderedChildren = null;
+    },
+
+    /**
+     * Moves a child component to the supplied index.
+     *
+     * @param {ReactComponent} child Component to move.
+     * @param {number} toIndex Destination index of the element.
+     * @param {number} lastIndex Last index visited of the siblings of `child`.
+     * @protected
+     */
+    moveChild: function(child, toIndex, lastIndex) {
+      // If the index of `child` is less than `lastIndex`, then it needs to
+      // be moved. Otherwise, we do not need to move it because a child will be
+      // inserted or moved before `child`.
+      if (child._mountIndex < lastIndex) {
+        enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
+      }
+    },
+
+    /**
+     * Creates a child component.
+     *
+     * @param {ReactComponent} child Component to create.
+     * @param {string} mountImage Markup to insert.
+     * @protected
+     */
+    createChild: function(child, mountImage) {
+      enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
+    },
+
+    /**
+     * Removes a child component.
+     *
+     * @param {ReactComponent} child Child to remove.
+     * @protected
+     */
+    removeChild: function(child) {
+      enqueueRemove(this._rootNodeID, child._mountIndex);
+    },
+
+    /**
+     * Sets this text content string.
+     *
+     * @param {string} textContent Text content to set.
+     * @protected
+     */
+    setTextContent: function(textContent) {
+      enqueueTextContent(this._rootNodeID, textContent);
+    },
+
+    /**
+     * Mounts a child with the supplied name.
+     *
+     * NOTE: This is part of `updateChildren` and is here for readability.
+     *
+     * @param {ReactComponent} child Component to mount.
+     * @param {string} name Name of the child.
+     * @param {number} index Index at which to insert the child.
+     * @param {ReactReconcileTransaction} transaction
+     * @private
+     */
+    _mountChildByNameAtIndex: function(
+      child,
+      name,
+      index,
+      transaction,
+      context) {
+      // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+      var rootID = this._rootNodeID + name;
+      var mountImage = ReactReconciler.mountComponent(
+        child,
+        rootID,
+        transaction,
+        context
+      );
+      child._mountIndex = index;
+      this.createChild(child, mountImage);
+    },
+
+    /**
+     * Unmounts a rendered child by name.
+     *
+     * NOTE: This is part of `updateChildren` and is here for readability.
+     *
+     * @param {ReactComponent} child Component to unmount.
+     * @param {string} name Name of the child in `this._renderedChildren`.
+     * @private
+     */
+    _unmountChildByName: function(child, name) {
+      this.removeChild(child);
+      child._mountIndex = null;
+    }
+
+  }
+
+};
+
+module.exports = ReactMultiChild;
+
+},{"31":31,"36":36,"72":72,"81":81}],72:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChildUpdateTypes
+ */
+
+'use strict';
+
+var keyMirror = _dereq_(140);
+
+/**
+ * When a component's children are updated, a series of update configuration
+ * objects are created in order to batch and serialize the required changes.
+ *
+ * Enumerates all the possible types of update configurations.
+ *
+ * @internal
+ */
+var ReactMultiChildUpdateTypes = keyMirror({
+  INSERT_MARKUP: null,
+  MOVE_EXISTING: null,
+  REMOVE_NODE: null,
+  TEXT_CONTENT: null
+});
+
+module.exports = ReactMultiChildUpdateTypes;
+
+},{"140":140}],73:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactNativeComponent
+ */
+
+'use strict';
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+
+var autoGenerateWrapperClass = null;
+var genericComponentClass = null;
+// This registry keeps track of wrapper classes around native tags
+var tagToComponentClass = {};
+var textComponentClass = null;
+
+var ReactNativeComponentInjection = {
+  // This accepts a class that receives the tag string. This is a catch all
+  // that can render any kind of tag.
+  injectGenericComponentClass: function(componentClass) {
+    genericComponentClass = componentClass;
+  },
+  // This accepts a text component class that takes the text string to be
+  // rendered as props.
+  injectTextComponentClass: function(componentClass) {
+    textComponentClass = componentClass;
+  },
+  // This accepts a keyed object with classes as values. Each key represents a
+  // tag. That particular tag will use this class instead of the generic one.
+  injectComponentClasses: function(componentClasses) {
+    assign(tagToComponentClass, componentClasses);
+  },
+  // Temporary hack since we expect DOM refs to behave like composites,
+  // for this release.
+  injectAutoWrapper: function(wrapperFactory) {
+    autoGenerateWrapperClass = wrapperFactory;
+  }
+};
+
+/**
+ * Get a composite component wrapper class for a specific tag.
+ *
+ * @param {ReactElement} element The tag for which to get the class.
+ * @return {function} The React class constructor function.
+ */
+function getComponentClassForElement(element) {
+  if (typeof element.type === 'function') {
+    return element.type;
+  }
+  var tag = element.type;
+  var componentClass = tagToComponentClass[tag];
+  if (componentClass == null) {
+    tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
+  }
+  return componentClass;
+}
+
+/**
+ * Get a native internal component class for a specific tag.
+ *
+ * @param {ReactElement} element The element to create.
+ * @return {function} The internal class constructor function.
+ */
+function createInternalComponent(element) {
+  ("production" !== "development" ? invariant(
+    genericComponentClass,
+    'There is no registered component for the tag %s',
+    element.type
+  ) : invariant(genericComponentClass));
+  return new genericComponentClass(element.type, element.props);
+}
+
+/**
+ * @param {ReactText} text
+ * @return {ReactComponent}
+ */
+function createInstanceForText(text) {
+  return new textComponentClass(text);
+}
+
+/**
+ * @param {ReactComponent} component
+ * @return {boolean}
+ */
+function isTextComponent(component) {
+  return component instanceof textComponentClass;
+}
+
+var ReactNativeComponent = {
+  getComponentClassForElement: getComponentClassForElement,
+  createInternalComponent: createInternalComponent,
+  createInstanceForText: createInstanceForText,
+  isTextComponent: isTextComponent,
+  injection: ReactNativeComponentInjection
+};
+
+module.exports = ReactNativeComponent;
+
+},{"135":135,"27":27}],74:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactOwner
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ * ReactOwners are capable of storing references to owned components.
+ *
+ * All components are capable of //being// referenced by owner components, but
+ * only ReactOwner components are capable of //referencing// owned components.
+ * The named reference is known as a "ref".
+ *
+ * Refs are available when mounted and updated during reconciliation.
+ *
+ *   var MyComponent = React.createClass({
+ *     render: function() {
+ *       return (
+ *         <div onClick={this.handleClick}>
+ *           <CustomComponent ref="custom" />
+ *         </div>
+ *       );
+ *     },
+ *     handleClick: function() {
+ *       this.refs.custom.handleClick();
+ *     },
+ *     componentDidMount: function() {
+ *       this.refs.custom.initialize();
+ *     }
+ *   });
+ *
+ * Refs should rarely be used. When refs are used, they should only be done to
+ * control data that is not handled by React's data flow.
+ *
+ * @class ReactOwner
+ */
+var ReactOwner = {
+
+  /**
+   * @param {?object} object
+   * @return {boolean} True if `object` is a valid owner.
+   * @final
+   */
+  isValidOwner: function(object) {
+    return !!(
+      (object &&
+      typeof object.attachRef === 'function' && typeof object.detachRef === 'function')
+    );
+  },
+
+  /**
+   * Adds a component by ref to an owner component.
+   *
+   * @param {ReactComponent} component Component to reference.
+   * @param {string} ref Name by which to refer to the component.
+   * @param {ReactOwner} owner Component on which to record the ref.
+   * @final
+   * @internal
+   */
+  addComponentAsRefTo: function(component, ref, owner) {
+    ("production" !== "development" ? invariant(
+      ReactOwner.isValidOwner(owner),
+      'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
+      'usually means that you\'re trying to add a ref to a component that ' +
+      'doesn\'t have an owner (that is, was not created inside of another ' +
+      'component\'s `render` method). Try rendering this component inside of ' +
+      'a new top-level component which will hold the ref.'
+    ) : invariant(ReactOwner.isValidOwner(owner)));
+    owner.attachRef(ref, component);
+  },
+
+  /**
+   * Removes a component by ref from an owner component.
+   *
+   * @param {ReactComponent} component Component to dereference.
+   * @param {string} ref Name of the ref to remove.
+   * @param {ReactOwner} owner Component on which the ref is recorded.
+   * @final
+   * @internal
+   */
+  removeComponentAsRefFrom: function(component, ref, owner) {
+    ("production" !== "development" ? invariant(
+      ReactOwner.isValidOwner(owner),
+      'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
+      'usually means that you\'re trying to remove a ref to a component that ' +
+      'doesn\'t have an owner (that is, was not created inside of another ' +
+      'component\'s `render` method). Try rendering this component inside of ' +
+      'a new top-level component which will hold the ref.'
+    ) : invariant(ReactOwner.isValidOwner(owner)));
+    // Check that `component` is still the current ref because we do not want to
+    // detach the ref if another component stole it.
+    if (owner.getPublicInstance().refs[ref] === component.getPublicInstance()) {
+      owner.detachRef(ref);
+    }
+  }
+
+};
+
+module.exports = ReactOwner;
+
+},{"135":135}],75:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPerf
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * ReactPerf is a general AOP system designed to measure performance. This
+ * module only has the hooks: see ReactDefaultPerf for the analysis tool.
+ */
+var ReactPerf = {
+  /**
+   * Boolean to enable/disable measurement. Set to false by default to prevent
+   * accidental logging and perf loss.
+   */
+  enableMeasure: false,
+
+  /**
+   * Holds onto the measure function in use. By default, don't measure
+   * anything, but we'll override this if we inject a measure function.
+   */
+  storedMeasure: _noMeasure,
+
+  /**
+   * @param {object} object
+   * @param {string} objectName
+   * @param {object<string>} methodNames
+   */
+  measureMethods: function(object, objectName, methodNames) {
+    if ("production" !== "development") {
+      for (var key in methodNames) {
+        if (!methodNames.hasOwnProperty(key)) {
+          continue;
+        }
+        object[key] = ReactPerf.measure(
+          objectName,
+          methodNames[key],
+          object[key]
+        );
+      }
+    }
+  },
+
+  /**
+   * Use this to wrap methods you want to measure. Zero overhead in production.
+   *
+   * @param {string} objName
+   * @param {string} fnName
+   * @param {function} func
+   * @return {function}
+   */
+  measure: function(objName, fnName, func) {
+    if ("production" !== "development") {
+      var measuredFunc = null;
+      var wrapper = function() {
+        if (ReactPerf.enableMeasure) {
+          if (!measuredFunc) {
+            measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
+          }
+          return measuredFunc.apply(this, arguments);
+        }
+        return func.apply(this, arguments);
+      };
+      wrapper.displayName = objName + '_' + fnName;
+      return wrapper;
+    }
+    return func;
+  },
+
+  injection: {
+    /**
+     * @param {function} measure
+     */
+    injectMeasure: function(measure) {
+      ReactPerf.storedMeasure = measure;
+    }
+  }
+};
+
+/**
+ * Simply passes through the measured function, without measuring it.
+ *
+ * @param {string} objName
+ * @param {string} fnName
+ * @param {function} func
+ * @return {function}
+ */
+function _noMeasure(objName, fnName, func) {
+  return func;
+}
+
+module.exports = ReactPerf;
+
+},{}],76:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocationNames
+ */
+
+'use strict';
+
+var ReactPropTypeLocationNames = {};
+
+if ("production" !== "development") {
+  ReactPropTypeLocationNames = {
+    prop: 'prop',
+    context: 'context',
+    childContext: 'child context'
+  };
+}
+
+module.exports = ReactPropTypeLocationNames;
+
+},{}],77:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocations
+ */
+
+'use strict';
+
+var keyMirror = _dereq_(140);
+
+var ReactPropTypeLocations = keyMirror({
+  prop: null,
+  context: null,
+  childContext: null
+});
+
+module.exports = ReactPropTypeLocations;
+
+},{"140":140}],78:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypes
+ */
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactFragment = _dereq_(63);
+var ReactPropTypeLocationNames = _dereq_(76);
+
+var emptyFunction = _dereq_(114);
+
+/**
+ * Collection of methods that allow declaration and validation of props that are
+ * supplied to React components. Example usage:
+ *
+ *   var Props = require('ReactPropTypes');
+ *   var MyArticle = React.createClass({
+ *     propTypes: {
+ *       // An optional string prop named "description".
+ *       description: Props.string,
+ *
+ *       // A required enum prop named "category".
+ *       category: Props.oneOf(['News','Photos']).isRequired,
+ *
+ *       // A prop named "dialog" that requires an instance of Dialog.
+ *       dialog: Props.instanceOf(Dialog).isRequired
+ *     },
+ *     render: function() { ... }
+ *   });
+ *
+ * A more formal specification of how these methods are used:
+ *
+ *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
+ *   decl := ReactPropTypes.{type}(.isRequired)?
+ *
+ * Each and every declaration produces a function with the same signature. This
+ * allows the creation of custom validation functions. For example:
+ *
+ *  var MyLink = React.createClass({
+ *    propTypes: {
+ *      // An optional string or URI prop named "href".
+ *      href: function(props, propName, componentName) {
+ *        var propValue = props[propName];
+ *        if (propValue != null && typeof propValue !== 'string' &&
+ *            !(propValue instanceof URI)) {
+ *          return new Error(
+ *            'Expected a string or an URI for ' + propName + ' in ' +
+ *            componentName
+ *          );
+ *        }
+ *      }
+ *    },
+ *    render: function() {...}
+ *  });
+ *
+ * @internal
+ */
+
+var ANONYMOUS = '<<anonymous>>';
+
+var elementTypeChecker = createElementTypeChecker();
+var nodeTypeChecker = createNodeChecker();
+
+var ReactPropTypes = {
+  array: createPrimitiveTypeChecker('array'),
+  bool: createPrimitiveTypeChecker('boolean'),
+  func: createPrimitiveTypeChecker('function'),
+  number: createPrimitiveTypeChecker('number'),
+  object: createPrimitiveTypeChecker('object'),
+  string: createPrimitiveTypeChecker('string'),
+
+  any: createAnyTypeChecker(),
+  arrayOf: createArrayOfTypeChecker,
+  element: elementTypeChecker,
+  instanceOf: createInstanceTypeChecker,
+  node: nodeTypeChecker,
+  objectOf: createObjectOfTypeChecker,
+  oneOf: createEnumTypeChecker,
+  oneOfType: createUnionTypeChecker,
+  shape: createShapeTypeChecker
+};
+
+function createChainableTypeChecker(validate) {
+  function checkType(isRequired, props, propName, componentName, location) {
+    componentName = componentName || ANONYMOUS;
+    if (props[propName] == null) {
+      var locationName = ReactPropTypeLocationNames[location];
+      if (isRequired) {
+        return new Error(
+          ("Required " + locationName + " `" + propName + "` was not specified in ") +
+          ("`" + componentName + "`.")
+        );
+      }
+      return null;
+    } else {
+      return validate(props, propName, componentName, location);
+    }
+  }
+
+  var chainedCheckType = checkType.bind(null, false);
+  chainedCheckType.isRequired = checkType.bind(null, true);
+
+  return chainedCheckType;
+}
+
+function createPrimitiveTypeChecker(expectedType) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== expectedType) {
+      var locationName = ReactPropTypeLocationNames[location];
+      // `propValue` being instance of, say, date/regexp, pass the 'object'
+      // check, but we can offer a more precise error message here rather than
+      // 'of type `object`'.
+      var preciseType = getPreciseType(propValue);
+
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type `" + preciseType + "` ") +
+        ("supplied to `" + componentName + "`, expected `" + expectedType + "`.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createAnyTypeChecker() {
+  return createChainableTypeChecker(emptyFunction.thatReturns(null));
+}
+
+function createArrayOfTypeChecker(typeChecker) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    if (!Array.isArray(propValue)) {
+      var locationName = ReactPropTypeLocationNames[location];
+      var propType = getPropType(propValue);
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type ") +
+        ("`" + propType + "` supplied to `" + componentName + "`, expected an array.")
+      );
+    }
+    for (var i = 0; i < propValue.length; i++) {
+      var error = typeChecker(propValue, i, componentName, location);
+      if (error instanceof Error) {
+        return error;
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createElementTypeChecker() {
+  function validate(props, propName, componentName, location) {
+    if (!ReactElement.isValidElement(props[propName])) {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected a ReactElement.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createInstanceTypeChecker(expectedClass) {
+  function validate(props, propName, componentName, location) {
+    if (!(props[propName] instanceof expectedClass)) {
+      var locationName = ReactPropTypeLocationNames[location];
+      var expectedClassName = expectedClass.name || ANONYMOUS;
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected instance of `" + expectedClassName + "`.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createEnumTypeChecker(expectedValues) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    for (var i = 0; i < expectedValues.length; i++) {
+      if (propValue === expectedValues[i]) {
+        return null;
+      }
+    }
+
+    var locationName = ReactPropTypeLocationNames[location];
+    var valuesString = JSON.stringify(expectedValues);
+    return new Error(
+      ("Invalid " + locationName + " `" + propName + "` of value `" + propValue + "` ") +
+      ("supplied to `" + componentName + "`, expected one of " + valuesString + ".")
+    );
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createObjectOfTypeChecker(typeChecker) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== 'object') {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type ") +
+        ("`" + propType + "` supplied to `" + componentName + "`, expected an object.")
+      );
+    }
+    for (var key in propValue) {
+      if (propValue.hasOwnProperty(key)) {
+        var error = typeChecker(propValue, key, componentName, location);
+        if (error instanceof Error) {
+          return error;
+        }
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createUnionTypeChecker(arrayOfTypeCheckers) {
+  function validate(props, propName, componentName, location) {
+    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
+      var checker = arrayOfTypeCheckers[i];
+      if (checker(props, propName, componentName, location) == null) {
+        return null;
+      }
+    }
+
+    var locationName = ReactPropTypeLocationNames[location];
+    return new Error(
+      ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+      ("`" + componentName + "`.")
+    );
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createNodeChecker() {
+  function validate(props, propName, componentName, location) {
+    if (!isNode(props[propName])) {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected a ReactNode.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createShapeTypeChecker(shapeTypes) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== 'object') {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type `" + propType + "` ") +
+        ("supplied to `" + componentName + "`, expected `object`.")
+      );
+    }
+    for (var key in shapeTypes) {
+      var checker = shapeTypes[key];
+      if (!checker) {
+        continue;
+      }
+      var error = checker(propValue, key, componentName, location);
+      if (error) {
+        return error;
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function isNode(propValue) {
+  switch (typeof propValue) {
+    case 'number':
+    case 'string':
+    case 'undefined':
+      return true;
+    case 'boolean':
+      return !propValue;
+    case 'object':
+      if (Array.isArray(propValue)) {
+        return propValue.every(isNode);
+      }
+      if (propValue === null || ReactElement.isValidElement(propValue)) {
+        return true;
+      }
+      propValue = ReactFragment.extractIfFragment(propValue);
+      for (var k in propValue) {
+        if (!isNode(propValue[k])) {
+          return false;
+        }
+      }
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Equivalent of `typeof` but with special handling for array and regexp.
+function getPropType(propValue) {
+  var propType = typeof propValue;
+  if (Array.isArray(propValue)) {
+    return 'array';
+  }
+  if (propValue instanceof RegExp) {
+    // Old webkits (at least until Android 4.0) return 'function' rather than
+    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
+    // passes PropTypes.object.
+    return 'object';
+  }
+  return propType;
+}
+
+// This handles more types than `getPropType`. Only used for error messages.
+// See `createPrimitiveTypeChecker`.
+function getPreciseType(propValue) {
+  var propType = getPropType(propValue);
+  if (propType === 'object') {
+    if (propValue instanceof Date) {
+      return 'date';
+    } else if (propValue instanceof RegExp) {
+      return 'regexp';
+    }
+  }
+  return propType;
+}
+
+module.exports = ReactPropTypes;
+
+},{"114":114,"57":57,"63":63,"76":76}],79:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPutListenerQueue
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+var ReactBrowserEventEmitter = _dereq_(30);
+
+var assign = _dereq_(27);
+
+function ReactPutListenerQueue() {
+  this.listenersToPut = [];
+}
+
+assign(ReactPutListenerQueue.prototype, {
+  enqueuePutListener: function(rootNodeID, propKey, propValue) {
+    this.listenersToPut.push({
+      rootNodeID: rootNodeID,
+      propKey: propKey,
+      propValue: propValue
+    });
+  },
+
+  putListeners: function() {
+    for (var i = 0; i < this.listenersToPut.length; i++) {
+      var listenerToPut = this.listenersToPut[i];
+      ReactBrowserEventEmitter.putListener(
+        listenerToPut.rootNodeID,
+        listenerToPut.propKey,
+        listenerToPut.propValue
+      );
+    }
+  },
+
+  reset: function() {
+    this.listenersToPut.length = 0;
+  },
+
+  destructor: function() {
+    this.reset();
+  }
+});
+
+PooledClass.addPoolingTo(ReactPutListenerQueue);
+
+module.exports = ReactPutListenerQueue;
+
+},{"27":27,"28":28,"30":30}],80:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactReconcileTransaction
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CallbackQueue = _dereq_(6);
+var PooledClass = _dereq_(28);
+var ReactBrowserEventEmitter = _dereq_(30);
+var ReactInputSelection = _dereq_(65);
+var ReactPutListenerQueue = _dereq_(79);
+var Transaction = _dereq_(103);
+
+var assign = _dereq_(27);
+
+/**
+ * Ensures that, when possible, the selection range (currently selected text
+ * input) is not disturbed by performing the transaction.
+ */
+var SELECTION_RESTORATION = {
+  /**
+   * @return {Selection} Selection information.
+   */
+  initialize: ReactInputSelection.getSelectionInformation,
+  /**
+   * @param {Selection} sel Selection information returned from `initialize`.
+   */
+  close: ReactInputSelection.restoreSelection
+};
+
+/**
+ * Suppresses events (blur/focus) that could be inadvertently dispatched due to
+ * high level DOM manipulations (like temporarily removing a text input from the
+ * DOM).
+ */
+var EVENT_SUPPRESSION = {
+  /**
+   * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
+   * the reconciliation.
+   */
+  initialize: function() {
+    var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
+    ReactBrowserEventEmitter.setEnabled(false);
+    return currentlyEnabled;
+  },
+
+  /**
+   * @param {boolean} previouslyEnabled Enabled status of
+   *   `ReactBrowserEventEmitter` before the reconciliation occured. `close`
+   *   restores the previous value.
+   */
+  close: function(previouslyEnabled) {
+    ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
+  }
+};
+
+/**
+ * Provides a queue for collecting `componentDidMount` and
+ * `componentDidUpdate` callbacks during the the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+  /**
+   * Initializes the internal `onDOMReady` queue.
+   */
+  initialize: function() {
+    this.reactMountReady.reset();
+  },
+
+  /**
+   * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
+   */
+  close: function() {
+    this.reactMountReady.notifyAll();
+  }
+};
+
+var PUT_LISTENER_QUEUEING = {
+  initialize: function() {
+    this.putListenerQueue.reset();
+  },
+
+  close: function() {
+    this.putListenerQueue.putListeners();
+  }
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+  PUT_LISTENER_QUEUEING,
+  SELECTION_RESTORATION,
+  EVENT_SUPPRESSION,
+  ON_DOM_READY_QUEUEING
+];
+
+/**
+ * Currently:
+ * - The order that these are listed in the transaction is critical:
+ * - Suppresses events.
+ * - Restores selection range.
+ *
+ * Future:
+ * - Restore document/overflow scroll positions that were unintentionally
+ *   modified via DOM insertions above the top viewport boundary.
+ * - Implement/integrate with customized constraint based layout system and keep
+ *   track of which dimensions must be remeasured.
+ *
+ * @class ReactReconcileTransaction
+ */
+function ReactReconcileTransaction() {
+  this.reinitializeTransaction();
+  // Only server-side rendering really needs this option (see
+  // `ReactServerRendering`), but server-side uses
+  // `ReactServerRenderingTransaction` instead. This option is here so that it's
+  // accessible and defaults to false when `ReactDOMComponent` and
+  // `ReactTextComponent` checks it in `mountComponent`.`
+  this.renderToStaticMarkup = false;
+  this.reactMountReady = CallbackQueue.getPooled(null);
+  this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+  /**
+   * @see Transaction
+   * @abstract
+   * @final
+   * @return {array<object>} List of operation wrap proceedures.
+   *   TODO: convert to array<TransactionWrapper>
+   */
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  /**
+   * @return {object} The queue to collect `onDOMReady` callbacks with.
+   */
+  getReactMountReady: function() {
+    return this.reactMountReady;
+  },
+
+  getPutListenerQueue: function() {
+    return this.putListenerQueue;
+  },
+
+  /**
+   * `PooledClass` looks for this, and will invoke this before allowing this
+   * instance to be resused.
+   */
+  destructor: function() {
+    CallbackQueue.release(this.reactMountReady);
+    this.reactMountReady = null;
+
+    ReactPutListenerQueue.release(this.putListenerQueue);
+    this.putListenerQueue = null;
+  }
+};
+
+
+assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
+
+PooledClass.addPoolingTo(ReactReconcileTransaction);
+
+module.exports = ReactReconcileTransaction;
+
+},{"103":103,"27":27,"28":28,"30":30,"6":6,"65":65,"79":79}],81:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactReconciler
+ */
+
+'use strict';
+
+var ReactRef = _dereq_(82);
+var ReactElementValidator = _dereq_(58);
+
+/**
+ * Helper to call ReactRef.attachRefs with this composite component, split out
+ * to avoid allocations in the transaction mount-ready queue.
+ */
+function attachRefs() {
+  ReactRef.attachRefs(this, this._currentElement);
+}
+
+var ReactReconciler = {
+
+  /**
+   * Initializes the component, renders markup, and registers event listeners.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {?string} Rendered markup to be inserted into the DOM.
+   * @final
+   * @internal
+   */
+  mountComponent: function(internalInstance, rootID, transaction, context) {
+    var markup = internalInstance.mountComponent(rootID, transaction, context);
+    if ("production" !== "development") {
+      ReactElementValidator.checkAndWarnForMutatedProps(
+        internalInstance._currentElement
+      );
+    }
+    transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
+    return markup;
+  },
+
+  /**
+   * Releases any resources allocated by `mountComponent`.
+   *
+   * @final
+   * @internal
+   */
+  unmountComponent: function(internalInstance) {
+    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
+    internalInstance.unmountComponent();
+  },
+
+  /**
+   * Update a component using a new element.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {ReactElement} nextElement
+   * @param {ReactReconcileTransaction} transaction
+   * @param {object} context
+   * @internal
+   */
+  receiveComponent: function(
+    internalInstance, nextElement, transaction, context
+  ) {
+    var prevElement = internalInstance._currentElement;
+
+    if (nextElement === prevElement && nextElement._owner != null) {
+      // Since elements are immutable after the owner is rendered,
+      // we can do a cheap identity compare here to determine if this is a
+      // superfluous reconcile. It's possible for state to be mutable but such
+      // change should trigger an update of the owner which would recreate
+      // the element. We explicitly check for the existence of an owner since
+      // it's possible for an element created outside a composite to be
+      // deeply mutated and reused.
+      return;
+    }
+
+    if ("production" !== "development") {
+      ReactElementValidator.checkAndWarnForMutatedProps(nextElement);
+    }
+
+    var refsChanged = ReactRef.shouldUpdateRefs(
+      prevElement,
+      nextElement
+    );
+
+    if (refsChanged) {
+      ReactRef.detachRefs(internalInstance, prevElement);
+    }
+
+    internalInstance.receiveComponent(nextElement, transaction, context);
+
+    if (refsChanged) {
+      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
+    }
+  },
+
+  /**
+   * Flush any dirty changes in a component.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  performUpdateIfNecessary: function(
+    internalInstance,
+    transaction
+  ) {
+    internalInstance.performUpdateIfNecessary(transaction);
+  }
+
+};
+
+module.exports = ReactReconciler;
+
+},{"58":58,"82":82}],82:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactRef
+ */
+
+'use strict';
+
+var ReactOwner = _dereq_(74);
+
+var ReactRef = {};
+
+function attachRef(ref, component, owner) {
+  if (typeof ref === 'function') {
+    ref(component.getPublicInstance());
+  } else {
+    // Legacy ref
+    ReactOwner.addComponentAsRefTo(component, ref, owner);
+  }
+}
+
+function detachRef(ref, component, owner) {
+  if (typeof ref === 'function') {
+    ref(null);
+  } else {
+    // Legacy ref
+    ReactOwner.removeComponentAsRefFrom(component, ref, owner);
+  }
+}
+
+ReactRef.attachRefs = function(instance, element) {
+  var ref = element.ref;
+  if (ref != null) {
+    attachRef(ref, instance, element._owner);
+  }
+};
+
+ReactRef.shouldUpdateRefs = function(prevElement, nextElement) {
+  // If either the owner or a `ref` has changed, make sure the newest owner
+  // has stored a reference to `this`, and the previous owner (if different)
+  // has forgotten the reference to `this`. We use the element instead
+  // of the public this.props because the post processing cannot determine
+  // a ref. The ref conceptually lives on the element.
+
+  // TODO: Should this even be possible? The owner cannot change because
+  // it's forbidden by shouldUpdateReactComponent. The ref can change
+  // if you swap the keys of but not the refs. Reconsider where this check
+  // is made. It probably belongs where the key checking and
+  // instantiateReactComponent is done.
+
+  return (
+    nextElement._owner !== prevElement._owner ||
+    nextElement.ref !== prevElement.ref
+  );
+};
+
+ReactRef.detachRefs = function(instance, element) {
+  var ref = element.ref;
+  if (ref != null) {
+    detachRef(ref, instance, element._owner);
+  }
+};
+
+module.exports = ReactRef;
+
+},{"74":74}],83:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+var ReactRootIndexInjection = {
+  /**
+   * @param {function} _createReactRootIndex
+   */
+  injectCreateReactRootIndex: function(_createReactRootIndex) {
+    ReactRootIndex.createReactRootIndex = _createReactRootIndex;
+  }
+};
+
+var ReactRootIndex = {
+  createReactRootIndex: null,
+  injection: ReactRootIndexInjection
+};
+
+module.exports = ReactRootIndex;
+
+},{}],84:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks static-only
+ * @providesModule ReactServerRendering
+ */
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactInstanceHandles = _dereq_(66);
+var ReactMarkupChecksum = _dereq_(69);
+var ReactServerRenderingTransaction =
+  _dereq_(85);
+
+var emptyObject = _dereq_(115);
+var instantiateReactComponent = _dereq_(134);
+var invariant = _dereq_(135);
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup
+ */
+function renderToString(element) {
+  ("production" !== "development" ? invariant(
+    ReactElement.isValidElement(element),
+    'renderToString(): You must pass a valid ReactElement.'
+  ) : invariant(ReactElement.isValidElement(element)));
+
+  var transaction;
+  try {
+    var id = ReactInstanceHandles.createReactRootID();
+    transaction = ReactServerRenderingTransaction.getPooled(false);
+
+    return transaction.perform(function() {
+      var componentInstance = instantiateReactComponent(element, null);
+      var markup =
+        componentInstance.mountComponent(id, transaction, emptyObject);
+      return ReactMarkupChecksum.addChecksumToMarkup(markup);
+    }, null);
+  } finally {
+    ReactServerRenderingTransaction.release(transaction);
+  }
+}
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup, without the extra React ID and checksum
+ * (for generating static pages)
+ */
+function renderToStaticMarkup(element) {
+  ("production" !== "development" ? invariant(
+    ReactElement.isValidElement(element),
+    'renderToStaticMarkup(): You must pass a valid ReactElement.'
+  ) : invariant(ReactElement.isValidElement(element)));
+
+  var transaction;
+  try {
+    var id = ReactInstanceHandles.createReactRootID();
+    transaction = ReactServerRenderingTransaction.getPooled(true);
+
+    return transaction.perform(function() {
+      var componentInstance = instantiateReactComponent(element, null);
+      return componentInstance.mountComponent(id, transaction, emptyObject);
+    }, null);
+  } finally {
+    ReactServerRenderingTransaction.release(transaction);
+  }
+}
+
+module.exports = {
+  renderToString: renderToString,
+  renderToStaticMarkup: renderToStaticMarkup
+};
+
+},{"115":115,"134":134,"135":135,"57":57,"66":66,"69":69,"85":85}],85:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactServerRenderingTransaction
+ * @typechecks
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+var CallbackQueue = _dereq_(6);
+var ReactPutListenerQueue = _dereq_(79);
+var Transaction = _dereq_(103);
+
+var assign = _dereq_(27);
+var emptyFunction = _dereq_(114);
+
+/**
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
+ * during the performing of the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+  /**
+   * Initializes the internal `onDOMReady` queue.
+   */
+  initialize: function() {
+    this.reactMountReady.reset();
+  },
+
+  close: emptyFunction
+};
+
+var PUT_LISTENER_QUEUEING = {
+  initialize: function() {
+    this.putListenerQueue.reset();
+  },
+
+  close: emptyFunction
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+  PUT_LISTENER_QUEUEING,
+  ON_DOM_READY_QUEUEING
+];
+
+/**
+ * @class ReactServerRenderingTransaction
+ * @param {boolean} renderToStaticMarkup
+ */
+function ReactServerRenderingTransaction(renderToStaticMarkup) {
+  this.reinitializeTransaction();
+  this.renderToStaticMarkup = renderToStaticMarkup;
+  this.reactMountReady = CallbackQueue.getPooled(null);
+  this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+  /**
+   * @see Transaction
+   * @abstract
+   * @final
+   * @return {array} Empty list of operation wrap proceedures.
+   */
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  /**
+   * @return {object} The queue to collect `onDOMReady` callbacks with.
+   */
+  getReactMountReady: function() {
+    return this.reactMountReady;
+  },
+
+  getPutListenerQueue: function() {
+    return this.putListenerQueue;
+  },
+
+  /**
+   * `PooledClass` looks for this, and will invoke this before allowing this
+   * instance to be resused.
+   */
+  destructor: function() {
+    CallbackQueue.release(this.reactMountReady);
+    this.reactMountReady = null;
+
+    ReactPutListenerQueue.release(this.putListenerQueue);
+    this.putListenerQueue = null;
+  }
+};
+
+
+assign(
+  ReactServerRenderingTransaction.prototype,
+  Transaction.Mixin,
+  Mixin
+);
+
+PooledClass.addPoolingTo(ReactServerRenderingTransaction);
+
+module.exports = ReactServerRenderingTransaction;
+
+},{"103":103,"114":114,"27":27,"28":28,"6":6,"79":79}],86:[function(_dereq_,module,exports){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactUpdateQueue
+ */
+
+'use strict';
+
+var ReactLifeCycle = _dereq_(68);
+var ReactCurrentOwner = _dereq_(39);
+var ReactElement = _dereq_(57);
+var ReactInstanceMap = _dereq_(67);
+var ReactUpdates = _dereq_(87);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+function enqueueUpdate(internalInstance) {
+  if (internalInstance !== ReactLifeCycle.currentlyMountingInstance) {
+    // If we're in a componentWillMount handler, don't enqueue a rerender
+    // because ReactUpdates assumes we're in a browser context (which is
+    // wrong for server rendering) and we're about to do a render anyway.
+    // See bug in #1740.
+    ReactUpdates.enqueueUpdate(internalInstance);
+  }
+}
+
+function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
+  ("production" !== "development" ? invariant(
+    ReactCurrentOwner.current == null,
+    '%s(...): Cannot update during an existing state transition ' +
+    '(such as within `render`). Render methods should be a pure function ' +
+    'of props and state.',
+    callerName
+  ) : invariant(ReactCurrentOwner.current == null));
+
+  var internalInstance = ReactInstanceMap.get(publicInstance);
+  if (!internalInstance) {
+    if ("production" !== "development") {
+      // Only warn when we have a callerName. Otherwise we should be silent.
+      // We're probably calling from enqueueCallback. We don't want to warn
+      // there because we already warned for the corresponding lifecycle method.
+      ("production" !== "development" ? warning(
+        !callerName,
+        '%s(...): Can only update a mounted or mounting component. ' +
+        'This usually means you called %s() on an unmounted ' +
+        'component. This is a no-op.',
+        callerName,
+        callerName
+      ) : null);
+    }
+    return null;
+  }
+
+  if (internalInstance === ReactLifeCycle.currentlyUnmountingInstance) {
+    return null;
+  }
+
+  return internalInstance;
+}
+
+/**
+ * ReactUpdateQueue allows for state updates to be scheduled into a later
+ * reconciliation step.
+ */
+var ReactUpdateQueue = {
+
+  /**
+   * Enqueue a callback that will be executed after all the pending updates
+   * have processed.
+   *
+   * @param {ReactClass} publicInstance The instance to use as `this` context.
+   * @param {?function} callback Called after state is updated.
+   * @internal
+   */
+  enqueueCallback: function(publicInstance, callback) {
+    ("production" !== "development" ? invariant(
+      typeof callback === 'function',
+      'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
+      '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
+      'isn\'t callable.'
+    ) : invariant(typeof callback === 'function'));
+    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
+
+    // Previously we would throw an error if we didn't have an internal
+    // instance. Since we want to make it a no-op instead, we mirror the same
+    // behavior we have in other enqueue* methods.
+    // We also need to ignore callbacks in componentWillMount. See
+    // enqueueUpdates.
+    if (!internalInstance ||
+        internalInstance === ReactLifeCycle.currentlyMountingInstance) {
+      return null;
+    }
+
+    if (internalInstance._pendingCallbacks) {
+      internalInstance._pendingCallbacks.push(callback);
+    } else {
+      internalInstance._pendingCallbacks = [callback];
+    }
+    // TODO: The callback here is ignored when setState is called from
+    // componentWillMount. Either fix it or disallow doing so completely in
+    // favor of getInitialState. Alternatively, we can disallow
+    // componentWillMount during server-side rendering.
+    enqueueUpdate(internalInstance);
+  },
+
+  enqueueCallbackInternal: function(internalInstance, callback) {
+    ("production" !== "development" ? invariant(
+      typeof callback === 'function',
+      'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
+      '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
+      'isn\'t callable.'
+    ) : invariant(typeof callback === 'function'));
+    if (internalInstance._pendingCallbacks) {
+      internalInstance._pendingCallbacks.push(callback);
+    } else {
+      internalInstance._pendingCallbacks = [callback];
+    }
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Forces an update. This should only be invoked when it is known with
+   * certainty that we are **not** in a DOM transaction.
+   *
+   * You may want to call this when you know that some deeper aspect of the
+   * component's state has changed but `setState` was not called.
+   *
+   * This will not invoke `shouldUpdateComponent`, but it will invoke
+   * `componentWillUpdate` and `componentDidUpdate`.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @internal
+   */
+  enqueueForceUpdate: function(publicInstance) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'forceUpdate'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    internalInstance._pendingForceUpdate = true;
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Replaces all of the state. Always use this or `setState` to mutate state.
+   * You should treat `this.state` as immutable.
+   *
+   * There is no guarantee that `this.state` will be immediately updated, so
+   * accessing `this.state` after calling this method may return the old value.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} completeState Next state.
+   * @internal
+   */
+  enqueueReplaceState: function(publicInstance, completeState) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'replaceState'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    internalInstance._pendingStateQueue = [completeState];
+    internalInstance._pendingReplaceState = true;
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Sets a subset of the state. This only exists because _pendingState is
+   * internal. This provides a merging strategy that is not available to deep
+   * properties which is confusing. TODO: Expose pendingState or don't use it
+   * during the merge.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} partialState Next partial state to be merged with state.
+   * @internal
+   */
+  enqueueSetState: function(publicInstance, partialState) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'setState'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    var queue =
+      internalInstance._pendingStateQueue ||
+      (internalInstance._pendingStateQueue = []);
+    queue.push(partialState);
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Sets a subset of the props.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} partialProps Subset of the next props.
+   * @internal
+   */
+  enqueueSetProps: function(publicInstance, partialProps) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'setProps'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    ("production" !== "development" ? invariant(
+      internalInstance._isTopLevel,
+      'setProps(...): You called `setProps` on a ' +
+      'component with a parent. This is an anti-pattern since props will ' +
+      'get reactively updated when rendered. Instead, change the owner\'s ' +
+      '`render` method to pass the correct value as props to the component ' +
+      'where it is created.'
+    ) : invariant(internalInstance._isTopLevel));
+
+    // Merge with the pending element if it exists, otherwise with existing
+    // element props.
+    var element = internalInstance._pendingElement ||
+                  internalInstance._currentElement;
+    var props = assign({}, element.props, partialProps);
+    internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      props
+    );
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Replaces all of the props.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} props New props.
+   * @internal
+   */
+  enqueueReplaceProps: function(publicInstance, props) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'replaceProps'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    ("production" !== "development" ? invariant(
+      internalInstance._isTopLevel,
+      'replaceProps(...): You called `replaceProps` on a ' +
+      'component with a parent. This is an anti-pattern since props will ' +
+      'get reactively updated when rendered. Instead, change the owner\'s ' +
+      '`render` method to pass the correct value as props to the component ' +
+      'where it is created.'
+    ) : invariant(internalInstance._isTopLevel));
+
+    // Merge with the pending element if it exists, otherwise with existing
+    // element props.
+    var element = internalInstance._pendingElement ||
+                  internalInstance._currentElement;
+    internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      props
+    );
+
+    enqueueUpdate(internalInstance);
+  },
+
+  enqueueElementInternal: function(internalInstance, newElement) {
+    internalInstance._pendingElement = newElement;
+    enqueueUpdate(internalInstance);
+  }
+
+};
+
+module.exports = ReactUpdateQueue;
+
+},{"135":135,"154":154,"27":27,"39":39,"57":57,"67":67,"68":68,"87":87}],87:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactUpdates
+ */
+
+'use strict';
+
+var CallbackQueue = _dereq_(6);
+var PooledClass = _dereq_(28);
+var ReactCurrentOwner = _dereq_(39);
+var ReactPerf = _dereq_(75);
+var ReactReconciler = _dereq_(81);
+var Transaction = _dereq_(103);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+var dirtyComponents = [];
+var asapCallbackQueue = CallbackQueue.getPooled();
+var asapEnqueued = false;
+
+var batchingStrategy = null;
+
+function ensureInjected() {
+  ("production" !== "development" ? invariant(
+    ReactUpdates.ReactReconcileTransaction && batchingStrategy,
+    'ReactUpdates: must inject a reconcile transaction class and batching ' +
+    'strategy'
+  ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy));
+}
+
+var NESTED_UPDATES = {
+  initialize: function() {
+    this.dirtyComponentsLength = dirtyComponents.length;
+  },
+  close: function() {
+    if (this.dirtyComponentsLength !== dirtyComponents.length) {
+      // Additional updates were enqueued by componentDidUpdate handlers or
+      // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
+      // these new updates so that if A's componentDidUpdate calls setState on
+      // B, B will update before the callback A's updater provided when calling
+      // setState.
+      dirtyComponents.splice(0, this.dirtyComponentsLength);
+      flushBatchedUpdates();
+    } else {
+      dirtyComponents.length = 0;
+    }
+  }
+};
+
+var UPDATE_QUEUEING = {
+  initialize: function() {
+    this.callbackQueue.reset();
+  },
+  close: function() {
+    this.callbackQueue.notifyAll();
+  }
+};
+
+var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];
+
+function ReactUpdatesFlushTransaction() {
+  this.reinitializeTransaction();
+  this.dirtyComponentsLength = null;
+  this.callbackQueue = CallbackQueue.getPooled();
+  this.reconcileTransaction =
+    ReactUpdates.ReactReconcileTransaction.getPooled();
+}
+
+assign(
+  ReactUpdatesFlushTransaction.prototype,
+  Transaction.Mixin, {
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  destructor: function() {
+    this.dirtyComponentsLength = null;
+    CallbackQueue.release(this.callbackQueue);
+    this.callbackQueue = null;
+    ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
+    this.reconcileTransaction = null;
+  },
+
+  perform: function(method, scope, a) {
+    // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
+    // with this transaction's wrappers around it.
+    return Transaction.Mixin.perform.call(
+      this,
+      this.reconcileTransaction.perform,
+      this.reconcileTransaction,
+      method,
+      scope,
+      a
+    );
+  }
+});
+
+PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
+
+function batchedUpdates(callback, a, b, c, d) {
+  ensureInjected();
+  batchingStrategy.batchedUpdates(callback, a, b, c, d);
+}
+
+/**
+ * Array comparator for ReactComponents by mount ordering.
+ *
+ * @param {ReactComponent} c1 first component you're comparing
+ * @param {ReactComponent} c2 second component you're comparing
+ * @return {number} Return value usable by Array.prototype.sort().
+ */
+function mountOrderComparator(c1, c2) {
+  return c1._mountOrder - c2._mountOrder;
+}
+
+function runBatchedUpdates(transaction) {
+  var len = transaction.dirtyComponentsLength;
+  ("production" !== "development" ? invariant(
+    len === dirtyComponents.length,
+    'Expected flush transaction\'s stored dirty-components length (%s) to ' +
+    'match dirty-components array length (%s).',
+    len,
+    dirtyComponents.length
+  ) : invariant(len === dirtyComponents.length));
+
+  // Since reconciling a component higher in the owner hierarchy usually (not
+  // always -- see shouldComponentUpdate()) will reconcile children, reconcile
+  // them before their children by sorting the array.
+  dirtyComponents.sort(mountOrderComparator);
+
+  for (var i = 0; i < len; i++) {
+    // If a component is unmounted before pending changes apply, it will still
+    // be here, but we assume that it has cleared its _pendingCallbacks and
+    // that performUpdateIfNecessary is a noop.
+    var component = dirtyComponents[i];
+
+    // If performUpdateIfNecessary happens to enqueue any new updates, we
+    // shouldn't execute the callbacks until the next render happens, so
+    // stash the callbacks first
+    var callbacks = component._pendingCallbacks;
+    component._pendingCallbacks = null;
+
+    ReactReconciler.performUpdateIfNecessary(
+      component,
+      transaction.reconcileTransaction
+    );
+
+    if (callbacks) {
+      for (var j = 0; j < callbacks.length; j++) {
+        transaction.callbackQueue.enqueue(
+          callbacks[j],
+          component.getPublicInstance()
+        );
+      }
+    }
+  }
+}
+
+var flushBatchedUpdates = function() {
+  // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
+  // array and perform any updates enqueued by mount-ready handlers (i.e.,
+  // componentDidUpdate) but we need to check here too in order to catch
+  // updates enqueued by setState callbacks and asap calls.
+  while (dirtyComponents.length || asapEnqueued) {
+    if (dirtyComponents.length) {
+      var transaction = ReactUpdatesFlushTransaction.getPooled();
+      transaction.perform(runBatchedUpdates, null, transaction);
+      ReactUpdatesFlushTransaction.release(transaction);
+    }
+
+    if (asapEnqueued) {
+      asapEnqueued = false;
+      var queue = asapCallbackQueue;
+      asapCallbackQueue = CallbackQueue.getPooled();
+      queue.notifyAll();
+      CallbackQueue.release(queue);
+    }
+  }
+};
+flushBatchedUpdates = ReactPerf.measure(
+  'ReactUpdates',
+  'flushBatchedUpdates',
+  flushBatchedUpdates
+);
+
+/**
+ * Mark a component as needing a rerender, adding an optional callback to a
+ * list of functions which will be executed once the rerender occurs.
+ */
+function enqueueUpdate(component) {
+  ensureInjected();
+
+  // Various parts of our code (such as ReactCompositeComponent's
+  // _renderValidatedComponent) assume that calls to render aren't nested;
+  // verify that that's the case. (This is called by each top-level update
+  // function, like setProps, setState, forceUpdate, etc.; creation and
+  // destruction of top-level components is guarded in ReactMount.)
+  ("production" !== "development" ? warning(
+    ReactCurrentOwner.current == null,
+    'enqueueUpdate(): Render methods should be a pure function of props ' +
+    'and state; triggering nested component updates from render is not ' +
+    'allowed. If necessary, trigger nested updates in ' +
+    'componentDidUpdate.'
+  ) : null);
+
+  if (!batchingStrategy.isBatchingUpdates) {
+    batchingStrategy.batchedUpdates(enqueueUpdate, component);
+    return;
+  }
+
+  dirtyComponents.push(component);
+}
+
+/**
+ * Enqueue a callback to be run at the end of the current batching cycle. Throws
+ * if no updates are currently being performed.
+ */
+function asap(callback, context) {
+  ("production" !== "development" ? invariant(
+    batchingStrategy.isBatchingUpdates,
+    'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
+    'updates are not being batched.'
+  ) : invariant(batchingStrategy.isBatchingUpdates));
+  asapCallbackQueue.enqueue(callback, context);
+  asapEnqueued = true;
+}
+
+var ReactUpdatesInjection = {
+  injectReconcileTransaction: function(ReconcileTransaction) {
+    ("production" !== "development" ? invariant(
+      ReconcileTransaction,
+      'ReactUpdates: must provide a reconcile transaction class'
+    ) : invariant(ReconcileTransaction));
+    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
+  },
+
+  injectBatchingStrategy: function(_batchingStrategy) {
+    ("production" !== "development" ? invariant(
+      _batchingStrategy,
+      'ReactUpdates: must provide a batching strategy'
+    ) : invariant(_batchingStrategy));
+    ("production" !== "development" ? invariant(
+      typeof _batchingStrategy.batchedUpdates === 'function',
+      'ReactUpdates: must provide a batchedUpdates() function'
+    ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function'));
+    ("production" !== "development" ? invariant(
+      typeof _batchingStrategy.isBatchingUpdates === 'boolean',
+      'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
+    ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean'));
+    batchingStrategy = _batchingStrategy;
+  }
+};
+
+var ReactUpdates = {
+  /**
+   * React references `ReactReconcileTransaction` using this property in order
+   * to allow dependency injection.
+   *
+   * @internal
+   */
+  ReactReconcileTransaction: null,
+
+  batchedUpdates: batchedUpdates,
+  enqueueUpdate: enqueueUpdate,
+  flushBatchedUpdates: flushBatchedUpdates,
+  injection: ReactUpdatesInjection,
+  asap: asap
+};
+
+module.exports = ReactUpdates;
+
+},{"103":103,"135":135,"154":154,"27":27,"28":28,"39":39,"6":6,"75":75,"81":81}],88:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SVGDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+'use strict';
+
+var DOMProperty = _dereq_(10);
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+
+var SVGDOMPropertyConfig = {
+  Properties: {
+    cx: MUST_USE_ATTRIBUTE,
+    cy: MUST_USE_ATTRIBUTE,
+    d: MUST_USE_ATTRIBUTE,
+    dx: MUST_USE_ATTRIBUTE,
+    dy: MUST_USE_ATTRIBUTE,
+    fill: MUST_USE_ATTRIBUTE,
+    fillOpacity: MUST_USE_ATTRIBUTE,
+    fontFamily: MUST_USE_ATTRIBUTE,
+    fontSize: MUST_USE_ATTRIBUTE,
+    fx: MUST_USE_ATTRIBUTE,
+    fy: MUST_USE_ATTRIBUTE,
+    gradientTransform: MUST_USE_ATTRIBUTE,
+    gradientUnits: MUST_USE_ATTRIBUTE,
+    markerEnd: MUST_USE_ATTRIBUTE,
+    markerMid: MUST_USE_ATTRIBUTE,
+    markerStart: MUST_USE_ATTRIBUTE,
+    offset: MUST_USE_ATTRIBUTE,
+    opacity: MUST_USE_ATTRIBUTE,
+    patternContentUnits: MUST_USE_ATTRIBUTE,
+    patternUnits: MUST_USE_ATTRIBUTE,
+    points: MUST_USE_ATTRIBUTE,
+    preserveAspectRatio: MUST_USE_ATTRIBUTE,
+    r: MUST_USE_ATTRIBUTE,
+    rx: MUST_USE_ATTRIBUTE,
+    ry: MUST_USE_ATTRIBUTE,
+    spreadMethod: MUST_USE_ATTRIBUTE,
+    stopColor: MUST_USE_ATTRIBUTE,
+    stopOpacity: MUST_USE_ATTRIBUTE,
+    stroke: MUST_USE_ATTRIBUTE,
+    strokeDasharray: MUST_USE_ATTRIBUTE,
+    strokeLinecap: MUST_USE_ATTRIBUTE,
+    strokeOpacity: MUST_USE_ATTRIBUTE,
+    strokeWidth: MUST_USE_ATTRIBUTE,
+    textAnchor: MUST_USE_ATTRIBUTE,
+    transform: MUST_USE_ATTRIBUTE,
+    version: MUST_USE_ATTRIBUTE,
+    viewBox: MUST_USE_ATTRIBUTE,
+    x1: MUST_USE_ATTRIBUTE,
+    x2: MUST_USE_ATTRIBUTE,
+    x: MUST_USE_ATTRIBUTE,
+    y1: MUST_USE_ATTRIBUTE,
+    y2: MUST_USE_ATTRIBUTE,
+    y: MUST_USE_ATTRIBUTE
+  },
+  DOMAttributeNames: {
+    fillOpacity: 'fill-opacity',
+    fontFamily: 'font-family',
+    fontSize: 'font-size',
+    gradientTransform: 'gradientTransform',
+    gradientUnits: 'gradientUnits',
+    markerEnd: 'marker-end',
+    markerMid: 'marker-mid',
+    markerStart: 'marker-start',
+    patternContentUnits: 'patternContentUnits',
+    patternUnits: 'patternUnits',
+    preserveAspectRatio: 'preserveAspectRatio',
+    spreadMethod: 'spreadMethod',
+    stopColor: 'stop-color',
+    stopOpacity: 'stop-opacity',
+    strokeDasharray: 'stroke-dasharray',
+    strokeLinecap: 'stroke-linecap',
+    strokeOpacity: 'stroke-opacity',
+    strokeWidth: 'stroke-width',
+    textAnchor: 'text-anchor',
+    viewBox: 'viewBox'
+  }
+};
+
+module.exports = SVGDOMPropertyConfig;
+
+},{"10":10}],89:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SelectEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPropagators = _dereq_(20);
+var ReactInputSelection = _dereq_(65);
+var SyntheticEvent = _dereq_(95);
+
+var getActiveElement = _dereq_(121);
+var isTextInputElement = _dereq_(138);
+var keyOf = _dereq_(141);
+var shallowEqual = _dereq_(150);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  select: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onSelect: null}),
+      captured: keyOf({onSelectCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topContextMenu,
+      topLevelTypes.topFocus,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topMouseDown,
+      topLevelTypes.topMouseUp,
+      topLevelTypes.topSelectionChange
+    ]
+  }
+};
+
+var activeElement = null;
+var activeElementID = null;
+var lastSelection = null;
+var mouseDown = false;
+
+/**
+ * Get an object which is a unique representation of the current selection.
+ *
+ * The return value will not be consistent across nodes or browsers, but
+ * two identical selections on the same node will return identical objects.
+ *
+ * @param {DOMElement} node
+ * @param {object}
+ */
+function getSelection(node) {
+  if ('selectionStart' in node &&
+      ReactInputSelection.hasSelectionCapabilities(node)) {
+    return {
+      start: node.selectionStart,
+      end: node.selectionEnd
+    };
+  } else if (window.getSelection) {
+    var selection = window.getSelection();
+    return {
+      anchorNode: selection.anchorNode,
+      anchorOffset: selection.anchorOffset,
+      focusNode: selection.focusNode,
+      focusOffset: selection.focusOffset
+    };
+  } else if (document.selection) {
+    var range = document.selection.createRange();
+    return {
+      parentElement: range.parentElement(),
+      text: range.text,
+      top: range.boundingTop,
+      left: range.boundingLeft
+    };
+  }
+}
+
+/**
+ * Poll selection to see whether it's changed.
+ *
+ * @param {object} nativeEvent
+ * @return {?SyntheticEvent}
+ */
+function constructSelectEvent(nativeEvent) {
+  // Ensure we have the right element, and that the user is not dragging a
+  // selection (this matches native `select` event behavior). In HTML5, select
+  // fires only on input and textarea thus if there's no focused element we
+  // won't dispatch.
+  if (mouseDown ||
+      activeElement == null ||
+      activeElement !== getActiveElement()) {
+    return null;
+  }
+
+  // Only fire when selection has actually changed.
+  var currentSelection = getSelection(activeElement);
+  if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
+    lastSelection = currentSelection;
+
+    var syntheticEvent = SyntheticEvent.getPooled(
+      eventTypes.select,
+      activeElementID,
+      nativeEvent
+    );
+
+    syntheticEvent.type = 'select';
+    syntheticEvent.target = activeElement;
+
+    EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);
+
+    return syntheticEvent;
+  }
+}
+
+/**
+ * This plugin creates an `onSelect` event that normalizes select events
+ * across form elements.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - contentEditable
+ *
+ * This differs from native browser implementations in the following ways:
+ * - Fires on contentEditable fields as well as inputs.
+ * - Fires for collapsed selection.
+ * - Fires after user input.
+ */
+var SelectEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+
+    switch (topLevelType) {
+      // Track the input node that has focus.
+      case topLevelTypes.topFocus:
+        if (isTextInputElement(topLevelTarget) ||
+            topLevelTarget.contentEditable === 'true') {
+          activeElement = topLevelTarget;
+          activeElementID = topLevelTargetID;
+          lastSelection = null;
+        }
+        break;
+      case topLevelTypes.topBlur:
+        activeElement = null;
+        activeElementID = null;
+        lastSelection = null;
+        break;
+
+      // Don't fire the event while the user is dragging. This matches the
+      // semantics of the native select event.
+      case topLevelTypes.topMouseDown:
+        mouseDown = true;
+        break;
+      case topLevelTypes.topContextMenu:
+      case topLevelTypes.topMouseUp:
+        mouseDown = false;
+        return constructSelectEvent(nativeEvent);
+
+      // Chrome and IE fire non-standard event when selection is changed (and
+      // sometimes when it hasn't).
+      // Firefox doesn't support selectionchange, so check selection status
+      // after each key entry. The selection changes after keydown and before
+      // keyup, but we check on keydown as well in the case of holding down a
+      // key, when multiple keydown events are fired but only one keyup is.
+      case topLevelTypes.topSelectionChange:
+      case topLevelTypes.topKeyDown:
+      case topLevelTypes.topKeyUp:
+        return constructSelectEvent(nativeEvent);
+    }
+  }
+};
+
+module.exports = SelectEventPlugin;
+
+},{"121":121,"138":138,"141":141,"15":15,"150":150,"20":20,"65":65,"95":95}],90:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ServerReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+/**
+ * Size of the reactRoot ID space. We generate random numbers for React root
+ * IDs and if there's a collision the events and DOM update system will
+ * get confused. In the future we need a way to generate GUIDs but for
+ * now this will work on a smaller scale.
+ */
+var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);
+
+var ServerReactRootIndex = {
+  createReactRootIndex: function() {
+    return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
+  }
+};
+
+module.exports = ServerReactRootIndex;
+
+},{}],91:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SimpleEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = _dereq_(15);
+var EventPluginUtils = _dereq_(19);
+var EventPropagators = _dereq_(20);
+var SyntheticClipboardEvent = _dereq_(92);
+var SyntheticEvent = _dereq_(95);
+var SyntheticFocusEvent = _dereq_(96);
+var SyntheticKeyboardEvent = _dereq_(98);
+var SyntheticMouseEvent = _dereq_(99);
+var SyntheticDragEvent = _dereq_(94);
+var SyntheticTouchEvent = _dereq_(100);
+var SyntheticUIEvent = _dereq_(101);
+var SyntheticWheelEvent = _dereq_(102);
+
+var getEventCharCode = _dereq_(122);
+
+var invariant = _dereq_(135);
+var keyOf = _dereq_(141);
+var warning = _dereq_(154);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  blur: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onBlur: true}),
+      captured: keyOf({onBlurCapture: true})
+    }
+  },
+  click: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onClick: true}),
+      captured: keyOf({onClickCapture: true})
+    }
+  },
+  contextMenu: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onContextMenu: true}),
+      captured: keyOf({onContextMenuCapture: true})
+    }
+  },
+  copy: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCopy: true}),
+      captured: keyOf({onCopyCapture: true})
+    }
+  },
+  cut: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCut: true}),
+      captured: keyOf({onCutCapture: true})
+    }
+  },
+  doubleClick: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDoubleClick: true}),
+      captured: keyOf({onDoubleClickCapture: true})
+    }
+  },
+  drag: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDrag: true}),
+      captured: keyOf({onDragCapture: true})
+    }
+  },
+  dragEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragEnd: true}),
+      captured: keyOf({onDragEndCapture: true})
+    }
+  },
+  dragEnter: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragEnter: true}),
+      captured: keyOf({onDragEnterCapture: true})
+    }
+  },
+  dragExit: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragExit: true}),
+      captured: keyOf({onDragExitCapture: true})
+    }
+  },
+  dragLeave: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragLeave: true}),
+      captured: keyOf({onDragLeaveCapture: true})
+    }
+  },
+  dragOver: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragOver: true}),
+      captured: keyOf({onDragOverCapture: true})
+    }
+  },
+  dragStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragStart: true}),
+      captured: keyOf({onDragStartCapture: true})
+    }
+  },
+  drop: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDrop: true}),
+      captured: keyOf({onDropCapture: true})
+    }
+  },
+  focus: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onFocus: true}),
+      captured: keyOf({onFocusCapture: true})
+    }
+  },
+  input: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onInput: true}),
+      captured: keyOf({onInputCapture: true})
+    }
+  },
+  keyDown: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyDown: true}),
+      captured: keyOf({onKeyDownCapture: true})
+    }
+  },
+  keyPress: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyPress: true}),
+      captured: keyOf({onKeyPressCapture: true})
+    }
+  },
+  keyUp: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyUp: true}),
+      captured: keyOf({onKeyUpCapture: true})
+    }
+  },
+  load: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onLoad: true}),
+      captured: keyOf({onLoadCapture: true})
+    }
+  },
+  error: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onError: true}),
+      captured: keyOf({onErrorCapture: true})
+    }
+  },
+  // Note: We do not allow listening to mouseOver events. Instead, use the
+  // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
+  mouseDown: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseDown: true}),
+      captured: keyOf({onMouseDownCapture: true})
+    }
+  },
+  mouseMove: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseMove: true}),
+      captured: keyOf({onMouseMoveCapture: true})
+    }
+  },
+  mouseOut: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseOut: true}),
+      captured: keyOf({onMouseOutCapture: true})
+    }
+  },
+  mouseOver: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseOver: true}),
+      captured: keyOf({onMouseOverCapture: true})
+    }
+  },
+  mouseUp: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseUp: true}),
+      captured: keyOf({onMouseUpCapture: true})
+    }
+  },
+  paste: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onPaste: true}),
+      captured: keyOf({onPasteCapture: true})
+    }
+  },
+  reset: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onReset: true}),
+      captured: keyOf({onResetCapture: true})
+    }
+  },
+  scroll: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onScroll: true}),
+      captured: keyOf({onScrollCapture: true})
+    }
+  },
+  submit: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onSubmit: true}),
+      captured: keyOf({onSubmitCapture: true})
+    }
+  },
+  touchCancel: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchCancel: true}),
+      captured: keyOf({onTouchCancelCapture: true})
+    }
+  },
+  touchEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchEnd: true}),
+      captured: keyOf({onTouchEndCapture: true})
+    }
+  },
+  touchMove: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchMove: true}),
+      captured: keyOf({onTouchMoveCapture: true})
+    }
+  },
+  touchStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchStart: true}),
+      captured: keyOf({onTouchStartCapture: true})
+    }
+  },
+  wheel: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onWheel: true}),
+      captured: keyOf({onWheelCapture: true})
+    }
+  }
+};
+
+var topLevelEventsToDispatchConfig = {
+  topBlur:        eventTypes.blur,
+  topClick:       eventTypes.click,
+  topContextMenu: eventTypes.contextMenu,
+  topCopy:        eventTypes.copy,
+  topCut:         eventTypes.cut,
+  topDoubleClick: eventTypes.doubleClick,
+  topDrag:        eventTypes.drag,
+  topDragEnd:     eventTypes.dragEnd,
+  topDragEnter:   eventTypes.dragEnter,
+  topDragExit:    eventTypes.dragExit,
+  topDragLeave:   eventTypes.dragLeave,
+  topDragOver:    eventTypes.dragOver,
+  topDragStart:   eventTypes.dragStart,
+  topDrop:        eventTypes.drop,
+  topError:       eventTypes.error,
+  topFocus:       eventTypes.focus,
+  topInput:       eventTypes.input,
+  topKeyDown:     eventTypes.keyDown,
+  topKeyPress:    eventTypes.keyPress,
+  topKeyUp:       eventTypes.keyUp,
+  topLoad:        eventTypes.load,
+  topMouseDown:   eventTypes.mouseDown,
+  topMouseMove:   eventTypes.mouseMove,
+  topMouseOut:    eventTypes.mouseOut,
+  topMouseOver:   eventTypes.mouseOver,
+  topMouseUp:     eventTypes.mouseUp,
+  topPaste:       eventTypes.paste,
+  topReset:       eventTypes.reset,
+  topScroll:      eventTypes.scroll,
+  topSubmit:      eventTypes.submit,
+  topTouchCancel: eventTypes.touchCancel,
+  topTouchEnd:    eventTypes.touchEnd,
+  topTouchMove:   eventTypes.touchMove,
+  topTouchStart:  eventTypes.touchStart,
+  topWheel:       eventTypes.wheel
+};
+
+for (var type in topLevelEventsToDispatchConfig) {
+  topLevelEventsToDispatchConfig[type].dependencies = [type];
+}
+
+var SimpleEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * Same as the default implementation, except cancels the event when return
+   * value is false. This behavior will be disabled in a future release.
+   *
+   * @param {object} Event to be dispatched.
+   * @param {function} Application-level callback.
+   * @param {string} domID DOM ID to pass to the callback.
+   */
+  executeDispatch: function(event, listener, domID) {
+    var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
+
+    ("production" !== "development" ? warning(
+      typeof returnValue !== 'boolean',
+      'Returning `false` from an event handler is deprecated and will be ' +
+      'ignored in a future release. Instead, manually call ' +
+      'e.stopPropagation() or e.preventDefault(), as appropriate.'
+    ) : null);
+
+    if (returnValue === false) {
+      event.stopPropagation();
+      event.preventDefault();
+    }
+  },
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
+    if (!dispatchConfig) {
+      return null;
+    }
+    var EventConstructor;
+    switch (topLevelType) {
+      case topLevelTypes.topInput:
+      case topLevelTypes.topLoad:
+      case topLevelTypes.topError:
+      case topLevelTypes.topReset:
+      case topLevelTypes.topSubmit:
+        // HTML Events
+        // @see http://www.w3.org/TR/html5/index.html#events-0
+        EventConstructor = SyntheticEvent;
+        break;
+      case topLevelTypes.topKeyPress:
+        // FireFox creates a keypress event for function keys too. This removes
+        // the unwanted keypress events. Enter is however both printable and
+        // non-printable. One would expect Tab to be as well (but it isn't).
+        if (getEventCharCode(nativeEvent) === 0) {
+          return null;
+        }
+        /* falls through */
+      case topLevelTypes.topKeyDown:
+      case topLevelTypes.topKeyUp:
+        EventConstructor = SyntheticKeyboardEvent;
+        break;
+      case topLevelTypes.topBlur:
+      case topLevelTypes.topFocus:
+        EventConstructor = SyntheticFocusEvent;
+        break;
+      case topLevelTypes.topClick:
+        // Firefox creates a click event on right mouse clicks. This removes the
+        // unwanted click events.
+        if (nativeEvent.button === 2) {
+          return null;
+        }
+        /* falls through */
+      case topLevelTypes.topContextMenu:
+      case topLevelTypes.topDoubleClick:
+      case topLevelTypes.topMouseDown:
+      case topLevelTypes.topMouseMove:
+      case topLevelTypes.topMouseOut:
+      case topLevelTypes.topMouseOver:
+      case topLevelTypes.topMouseUp:
+        EventConstructor = SyntheticMouseEvent;
+        break;
+      case topLevelTypes.topDrag:
+      case topLevelTypes.topDragEnd:
+      case topLevelTypes.topDragEnter:
+      case topLevelTypes.topDragExit:
+      case topLevelTypes.topDragLeave:
+      case topLevelTypes.topDragOver:
+      case topLevelTypes.topDragStart:
+      case topLevelTypes.topDrop:
+        EventConstructor = SyntheticDragEvent;
+        break;
+      case topLevelTypes.topTouchCancel:
+      case topLevelTypes.topTouchEnd:
+      case topLevelTypes.topTouchMove:
+      case topLevelTypes.topTouchStart:
+        EventConstructor = SyntheticTouchEvent;
+        break;
+      case topLevelTypes.topScroll:
+        EventConstructor = SyntheticUIEvent;
+        break;
+      case topLevelTypes.topWheel:
+        EventConstructor = SyntheticWheelEvent;
+        break;
+      case topLevelTypes.topCopy:
+      case topLevelTypes.topCut:
+      case topLevelTypes.topPaste:
+        EventConstructor = SyntheticClipboardEvent;
+        break;
+    }
+    ("production" !== "development" ? invariant(
+      EventConstructor,
+      'SimpleEventPlugin: Unhandled event type, `%s`.',
+      topLevelType
+    ) : invariant(EventConstructor));
+    var event = EventConstructor.getPooled(
+      dispatchConfig,
+      topLevelTargetID,
+      nativeEvent
+    );
+    EventPropagators.accumulateTwoPhaseDispatches(event);
+    return event;
+  }
+
+};
+
+module.exports = SimpleEventPlugin;
+
+},{"100":100,"101":101,"102":102,"122":122,"135":135,"141":141,"15":15,"154":154,"19":19,"20":20,"92":92,"94":94,"95":95,"96":96,"98":98,"99":99}],92:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticClipboardEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = _dereq_(95);
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/clipboard-apis/
+ */
+var ClipboardEventInterface = {
+  clipboardData: function(event) {
+    return (
+      'clipboardData' in event ?
+        event.clipboardData :
+        window.clipboardData
+    );
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
+
+module.exports = SyntheticClipboardEvent;
+
+},{"95":95}],93:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticCompositionEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = _dereq_(95);
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
+ */
+var CompositionEventInterface = {
+  data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticCompositionEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+  SyntheticCompositionEvent,
+  CompositionEventInterface
+);
+
+module.exports = SyntheticCompositionEvent;
+
+},{"95":95}],94:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticDragEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticMouseEvent = _dereq_(99);
+
+/**
+ * @interface DragEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var DragEventInterface = {
+  dataTransfer: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
+
+module.exports = SyntheticDragEvent;
+
+},{"99":99}],95:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var PooledClass = _dereq_(28);
+
+var assign = _dereq_(27);
+var emptyFunction = _dereq_(114);
+var getEventTarget = _dereq_(125);
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var EventInterface = {
+  type: null,
+  target: getEventTarget,
+  // currentTarget is set when dispatching; no use in copying it here
+  currentTarget: emptyFunction.thatReturnsNull,
+  eventPhase: null,
+  bubbles: null,
+  cancelable: null,
+  timeStamp: function(event) {
+    return event.timeStamp || Date.now();
+  },
+  defaultPrevented: null,
+  isTrusted: null
+};
+
+/**
+ * Synthetic events are dispatched by event plugins, typically in response to a
+ * top-level event delegation handler.
+ *
+ * These systems should generally use pooling to reduce the frequency of garbage
+ * collection. The system should check `isPersistent` to determine whether the
+ * event should be released into the pool after being dispatched. Users that
+ * need a persisted event should invoke `persist`.
+ *
+ * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
+ * normalizing browser quirks. Subclasses do not necessarily have to implement a
+ * DOM interface; custom application-specific events can also subclass this.
+ *
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ */
+function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  this.dispatchConfig = dispatchConfig;
+  this.dispatchMarker = dispatchMarker;
+  this.nativeEvent = nativeEvent;
+
+  var Interface = this.constructor.Interface;
+  for (var propName in Interface) {
+    if (!Interface.hasOwnProperty(propName)) {
+      continue;
+    }
+    var normalize = Interface[propName];
+    if (normalize) {
+      this[propName] = normalize(nativeEvent);
+    } else {
+      this[propName] = nativeEvent[propName];
+    }
+  }
+
+  var defaultPrevented = nativeEvent.defaultPrevented != null ?
+    nativeEvent.defaultPrevented :
+    nativeEvent.returnValue === false;
+  if (defaultPrevented) {
+    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+  } else {
+    this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
+  }
+  this.isPropagationStopped = emptyFunction.thatReturnsFalse;
+}
+
+assign(SyntheticEvent.prototype, {
+
+  preventDefault: function() {
+    this.defaultPrevented = true;
+    var event = this.nativeEvent;
+    if (event.preventDefault) {
+      event.preventDefault();
+    } else {
+      event.returnValue = false;
+    }
+    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+  },
+
+  stopPropagation: function() {
+    var event = this.nativeEvent;
+    if (event.stopPropagation) {
+      event.stopPropagation();
+    } else {
+      event.cancelBubble = true;
+    }
+    this.isPropagationStopped = emptyFunction.thatReturnsTrue;
+  },
+
+  /**
+   * We release all dispatched `SyntheticEvent`s after each event loop, adding
+   * them back into the pool. This allows a way to hold onto a reference that
+   * won't be added back into the pool.
+   */
+  persist: function() {
+    this.isPersistent = emptyFunction.thatReturnsTrue;
+  },
+
+  /**
+   * Checks if this event should be released back into the pool.
+   *
+   * @return {boolean} True if this should not be released, false otherwise.
+   */
+  isPersistent: emptyFunction.thatReturnsFalse,
+
+  /**
+   * `PooledClass` looks for `destructor` on each instance it releases.
+   */
+  destructor: function() {
+    var Interface = this.constructor.Interface;
+    for (var propName in Interface) {
+      this[propName] = null;
+    }
+    this.dispatchConfig = null;
+    this.dispatchMarker = null;
+    this.nativeEvent = null;
+  }
+
+});
+
+SyntheticEvent.Interface = EventInterface;
+
+/**
+ * Helper to reduce boilerplate when creating subclasses.
+ *
+ * @param {function} Class
+ * @param {?object} Interface
+ */
+SyntheticEvent.augmentClass = function(Class, Interface) {
+  var Super = this;
+
+  var prototype = Object.create(Super.prototype);
+  assign(prototype, Class.prototype);
+  Class.prototype = prototype;
+  Class.prototype.constructor = Class;
+
+  Class.Interface = assign({}, Super.Interface, Interface);
+  Class.augmentClass = Super.augmentClass;
+
+  PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
+};
+
+PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);
+
+module.exports = SyntheticEvent;
+
+},{"114":114,"125":125,"27":27,"28":28}],96:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticFocusEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = _dereq_(101);
+
+/**
+ * @interface FocusEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var FocusEventInterface = {
+  relatedTarget: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
+
+module.exports = SyntheticFocusEvent;
+
+},{"101":101}],97:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticInputEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = _dereq_(95);
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
+ *      /#events-inputevents
+ */
+var InputEventInterface = {
+  data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticInputEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+  SyntheticInputEvent,
+  InputEventInterface
+);
+
+module.exports = SyntheticInputEvent;
+
+},{"95":95}],98:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticKeyboardEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = _dereq_(101);
+
+var getEventCharCode = _dereq_(122);
+var getEventKey = _dereq_(123);
+var getEventModifierState = _dereq_(124);
+
+/**
+ * @interface KeyboardEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var KeyboardEventInterface = {
+  key: getEventKey,
+  location: null,
+  ctrlKey: null,
+  shiftKey: null,
+  altKey: null,
+  metaKey: null,
+  repeat: null,
+  locale: null,
+  getModifierState: getEventModifierState,
+  // Legacy Interface
+  charCode: function(event) {
+    // `charCode` is the result of a KeyPress event and represents the value of
+    // the actual printable character.
+
+    // KeyPress is deprecated, but its replacement is not yet final and not
+    // implemented in any major browser. Only KeyPress has charCode.
+    if (event.type === 'keypress') {
+      return getEventCharCode(event);
+    }
+    return 0;
+  },
+  keyCode: function(event) {
+    // `keyCode` is the result of a KeyDown/Up event and represents the value of
+    // physical keyboard key.
+
+    // The actual meaning of the value depends on the users' keyboard layout
+    // which cannot be detected. Assuming that it is a US keyboard layout
+    // provides a surprisingly accurate mapping for US and European users.
+    // Due to this, it is left to the user to implement at this time.
+    if (event.type === 'keydown' || event.type === 'keyup') {
+      return event.keyCode;
+    }
+    return 0;
+  },
+  which: function(event) {
+    // `which` is an alias for either `keyCode` or `charCode` depending on the
+    // type of the event.
+    if (event.type === 'keypress') {
+      return getEventCharCode(event);
+    }
+    if (event.type === 'keydown' || event.type === 'keyup') {
+      return event.keyCode;
+    }
+    return 0;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
+
+module.exports = SyntheticKeyboardEvent;
+
+},{"101":101,"122":122,"123":123,"124":124}],99:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticMouseEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = _dereq_(101);
+var ViewportMetrics = _dereq_(104);
+
+var getEventModifierState = _dereq_(124);
+
+/**
+ * @interface MouseEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var MouseEventInterface = {
+  screenX: null,
+  screenY: null,
+  clientX: null,
+  clientY: null,
+  ctrlKey: null,
+  shiftKey: null,
+  altKey: null,
+  metaKey: null,
+  getModifierState: getEventModifierState,
+  button: function(event) {
+    // Webkit, Firefox, IE9+
+    // which:  1 2 3
+    // button: 0 1 2 (standard)
+    var button = event.button;
+    if ('which' in event) {
+      return button;
+    }
+    // IE<9
+    // which:  undefined
+    // button: 0 0 0
+    // button: 1 4 2 (onmouseup)
+    return button === 2 ? 2 : button === 4 ? 1 : 0;
+  },
+  buttons: null,
+  relatedTarget: function(event) {
+    return event.relatedTarget || (
+      ((event.fromElement === event.srcElement ? event.toElement : event.fromElement))
+    );
+  },
+  // "Proprietary" Interface.
+  pageX: function(event) {
+    return 'pageX' in event ?
+      event.pageX :
+      event.clientX + ViewportMetrics.currentScrollLeft;
+  },
+  pageY: function(event) {
+    return 'pageY' in event ?
+      event.pageY :
+      event.clientY + ViewportMetrics.currentScrollTop;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
+
+module.exports = SyntheticMouseEvent;
+
+},{"101":101,"104":104,"124":124}],100:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticTouchEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = _dereq_(101);
+
+var getEventModifierState = _dereq_(124);
+
+/**
+ * @interface TouchEvent
+ * @see http://www.w3.org/TR/touch-events/
+ */
+var TouchEventInterface = {
+  touches: null,
+  targetTouches: null,
+  changedTouches: null,
+  altKey: null,
+  metaKey: null,
+  ctrlKey: null,
+  shiftKey: null,
+  getModifierState: getEventModifierState
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
+
+module.exports = SyntheticTouchEvent;
+
+},{"101":101,"124":124}],101:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticUIEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = _dereq_(95);
+
+var getEventTarget = _dereq_(125);
+
+/**
+ * @interface UIEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var UIEventInterface = {
+  view: function(event) {
+    if (event.view) {
+      return event.view;
+    }
+
+    var target = getEventTarget(event);
+    if (target != null && target.window === target) {
+      // target is a window object
+      return target;
+    }
+
+    var doc = target.ownerDocument;
+    // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+    if (doc) {
+      return doc.defaultView || doc.parentWindow;
+    } else {
+      return window;
+    }
+  },
+  detail: function(event) {
+    return event.detail || 0;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticEvent}
+ */
+function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
+
+module.exports = SyntheticUIEvent;
+
+},{"125":125,"95":95}],102:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticWheelEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticMouseEvent = _dereq_(99);
+
+/**
+ * @interface WheelEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var WheelEventInterface = {
+  deltaX: function(event) {
+    return (
+      'deltaX' in event ? event.deltaX :
+      // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
+      'wheelDeltaX' in event ? -event.wheelDeltaX : 0
+    );
+  },
+  deltaY: function(event) {
+    return (
+      'deltaY' in event ? event.deltaY :
+      // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
+      'wheelDeltaY' in event ? -event.wheelDeltaY :
+      // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
+      'wheelDelta' in event ? -event.wheelDelta : 0
+    );
+  },
+  deltaZ: null,
+
+  // Browsers without "deltaMode" is reporting in raw wheel delta where one
+  // notch on the scroll is always +/- 120, roughly equivalent to pixels.
+  // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
+  // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
+  deltaMode: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticMouseEvent}
+ */
+function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
+
+module.exports = SyntheticWheelEvent;
+
+},{"99":99}],103:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Transaction
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ * `Transaction` creates a black box that is able to wrap any method such that
+ * certain invariants are maintained before and after the method is invoked
+ * (Even if an exception is thrown while invoking the wrapped method). Whoever
+ * instantiates a transaction can provide enforcers of the invariants at
+ * creation time. The `Transaction` class itself will supply one additional
+ * automatic invariant for you - the invariant that any transaction instance
+ * should not be run while it is already being run. You would typically create a
+ * single instance of a `Transaction` for reuse multiple times, that potentially
+ * is used to wrap several different methods. Wrappers are extremely simple -
+ * they only require implementing two methods.
+ *
+ * <pre>
+ *                       wrappers (injected at creation time)
+ *                                      +        +
+ *                                      |        |
+ *                    +-----------------|--------|--------------+
+ *                    |                 v        |              |
+ *                    |      +---------------+   |              |
+ *                    |   +--|    wrapper1   |---|----+         |
+ *                    |   |  +---------------+   v    |         |
+ *                    |   |          +-------------+  |         |
+ *                    |   |     +----|   wrapper2  |--------+   |
+ *                    |   |     |    +-------------+  |     |   |
+ *                    |   |     |                     |     |   |
+ *                    |   v     v                     v     v   | wrapper
+ *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
+ * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+ * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | +---+ +---+   +---------+   +---+ +---+ |
+ *                    |  initialize                    close    |
+ *                    +-----------------------------------------+
+ * </pre>
+ *
+ * Use cases:
+ * - Preserving the input selection ranges before/after reconciliation.
+ *   Restoring selection even in the event of an unexpected error.
+ * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
+ *   while guaranteeing that afterwards, the event system is reactivated.
+ * - Flushing a queue of collected DOM mutations to the main UI thread after a
+ *   reconciliation takes place in a worker thread.
+ * - Invoking any collected `componentDidUpdate` callbacks after rendering new
+ *   content.
+ * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
+ *   to preserve the `scrollTop` (an automatic scroll aware DOM).
+ * - (Future use case): Layout calculations before and after DOM updates.
+ *
+ * Transactional plugin API:
+ * - A module that has an `initialize` method that returns any precomputation.
+ * - and a `close` method that accepts the precomputation. `close` is invoked
+ *   when the wrapped process is completed, or has failed.
+ *
+ * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
+ * that implement `initialize` and `close`.
+ * @return {Transaction} Single transaction for reuse in thread.
+ *
+ * @class Transaction
+ */
+var Mixin = {
+  /**
+   * Sets up this instance so that it is prepared for collecting metrics. Does
+   * so such that this setup method may be used on an instance that is already
+   * initialized, in a way that does not consume additional memory upon reuse.
+   * That can be useful if you decide to make your subclass of this mixin a
+   * "PooledClass".
+   */
+  reinitializeTransaction: function() {
+    this.transactionWrappers = this.getTransactionWrappers();
+    if (!this.wrapperInitData) {
+      this.wrapperInitData = [];
+    } else {
+      this.wrapperInitData.length = 0;
+    }
+    this._isInTransaction = false;
+  },
+
+  _isInTransaction: false,
+
+  /**
+   * @abstract
+   * @return {Array<TransactionWrapper>} Array of transaction wrappers.
+   */
+  getTransactionWrappers: null,
+
+  isInTransaction: function() {
+    return !!this._isInTransaction;
+  },
+
+  /**
+   * Executes the function within a safety window. Use this for the top level
+   * methods that result in large amounts of computation/mutations that would
+   * need to be safety checked.
+   *
+   * @param {function} method Member of scope to call.
+   * @param {Object} scope Scope to invoke from.
+   * @param {Object?=} args... Arguments to pass to the method (optional).
+   *                           Helps prevent need to bind in many cases.
+   * @return Return value from `method`.
+   */
+  perform: function(method, scope, a, b, c, d, e, f) {
+    ("production" !== "development" ? invariant(
+      !this.isInTransaction(),
+      'Transaction.perform(...): Cannot initialize a transaction when there ' +
+      'is already an outstanding transaction.'
+    ) : invariant(!this.isInTransaction()));
+    var errorThrown;
+    var ret;
+    try {
+      this._isInTransaction = true;
+      // Catching errors makes debugging more difficult, so we start with
+      // errorThrown set to true before setting it to false after calling
+      // close -- if it's still set to true in the finally block, it means
+      // one of these calls threw.
+      errorThrown = true;
+      this.initializeAll(0);
+      ret = method.call(scope, a, b, c, d, e, f);
+      errorThrown = false;
+    } finally {
+      try {
+        if (errorThrown) {
+          // If `method` throws, prefer to show that stack trace over any thrown
+          // by invoking `closeAll`.
+          try {
+            this.closeAll(0);
+          } catch (err) {
+          }
+        } else {
+          // Since `method` didn't throw, we don't want to silence the exception
+          // here.
+          this.closeAll(0);
+        }
+      } finally {
+        this._isInTransaction = false;
+      }
+    }
+    return ret;
+  },
+
+  initializeAll: function(startIndex) {
+    var transactionWrappers = this.transactionWrappers;
+    for (var i = startIndex; i < transactionWrappers.length; i++) {
+      var wrapper = transactionWrappers[i];
+      try {
+        // Catching errors makes debugging more difficult, so we start with the
+        // OBSERVED_ERROR state before overwriting it with the real return value
+        // of initialize -- if it's still set to OBSERVED_ERROR in the finally
+        // block, it means wrapper.initialize threw.
+        this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
+        this.wrapperInitData[i] = wrapper.initialize ?
+          wrapper.initialize.call(this) :
+          null;
+      } finally {
+        if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
+          // The initializer for wrapper i threw an error; initialize the
+          // remaining wrappers but silence any exceptions from them to ensure
+          // that the first error is the one to bubble up.
+          try {
+            this.initializeAll(i + 1);
+          } catch (err) {
+          }
+        }
+      }
+    }
+  },
+
+  /**
+   * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
+   * them the respective return values of `this.transactionWrappers.init[i]`
+   * (`close`rs that correspond to initializers that failed will not be
+   * invoked).
+   */
+  closeAll: function(startIndex) {
+    ("production" !== "development" ? invariant(
+      this.isInTransaction(),
+      'Transaction.closeAll(): Cannot close transaction when none are open.'
+    ) : invariant(this.isInTransaction()));
+    var transactionWrappers = this.transactionWrappers;
+    for (var i = startIndex; i < transactionWrappers.length; i++) {
+      var wrapper = transactionWrappers[i];
+      var initData = this.wrapperInitData[i];
+      var errorThrown;
+      try {
+        // Catching errors makes debugging more difficult, so we start with
+        // errorThrown set to true before setting it to false after calling
+        // close -- if it's still set to true in the finally block, it means
+        // wrapper.close threw.
+        errorThrown = true;
+        if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) {
+          wrapper.close.call(this, initData);
+        }
+        errorThrown = false;
+      } finally {
+        if (errorThrown) {
+          // The closer for wrapper i threw an error; close the remaining
+          // wrappers but silence any exceptions from them to ensure that the
+          // first error is the one to bubble up.
+          try {
+            this.closeAll(i + 1);
+          } catch (e) {
+          }
+        }
+      }
+    }
+    this.wrapperInitData.length = 0;
+  }
+};
+
+var Transaction = {
+
+  Mixin: Mixin,
+
+  /**
+   * Token to look for to determine if an error occured.
+   */
+  OBSERVED_ERROR: {}
+
+};
+
+module.exports = Transaction;
+
+},{"135":135}],104:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ViewportMetrics
+ */
+
+'use strict';
+
+var ViewportMetrics = {
+
+  currentScrollLeft: 0,
+
+  currentScrollTop: 0,
+
+  refreshScrollValues: function(scrollPosition) {
+    ViewportMetrics.currentScrollLeft = scrollPosition.x;
+    ViewportMetrics.currentScrollTop = scrollPosition.y;
+  }
+
+};
+
+module.exports = ViewportMetrics;
+
+},{}],105:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule accumulateInto
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ *
+ * Accumulates items that must not be null or undefined into the first one. This
+ * is used to conserve memory by avoiding array allocations, and thus sacrifices
+ * API cleanness. Since `current` can be null before being passed in and not
+ * null after this function, make sure to assign it back to `current`:
+ *
+ * `a = accumulateInto(a, b);`
+ *
+ * This API should be sparingly used. Try `accumulate` for something cleaner.
+ *
+ * @return {*|array<*>} An accumulation of items.
+ */
+
+function accumulateInto(current, next) {
+  ("production" !== "development" ? invariant(
+    next != null,
+    'accumulateInto(...): Accumulated items must not be null or undefined.'
+  ) : invariant(next != null));
+  if (current == null) {
+    return next;
+  }
+
+  // Both are not empty. Warning: Never call x.concat(y) when you are not
+  // certain that x is an Array (x could be a string with concat method).
+  var currentIsArray = Array.isArray(current);
+  var nextIsArray = Array.isArray(next);
+
+  if (currentIsArray && nextIsArray) {
+    current.push.apply(current, next);
+    return current;
+  }
+
+  if (currentIsArray) {
+    current.push(next);
+    return current;
+  }
+
+  if (nextIsArray) {
+    // A bit too dangerous to mutate `next`.
+    return [current].concat(next);
+  }
+
+  return [current, next];
+}
+
+module.exports = accumulateInto;
+
+},{"135":135}],106:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule adler32
+ */
+
+/* jslint bitwise:true */
+
+'use strict';
+
+var MOD = 65521;
+
+// This is a clean-room implementation of adler32 designed for detecting
+// if markup is not what we expect it to be. It does not need to be
+// cryptographically strong, only reasonably good at detecting if markup
+// generated on the server is different than that on the client.
+function adler32(data) {
+  var a = 1;
+  var b = 0;
+  for (var i = 0; i < data.length; i++) {
+    a = (a + data.charCodeAt(i)) % MOD;
+    b = (b + a) % MOD;
+  }
+  return a | (b << 16);
+}
+
+module.exports = adler32;
+
+},{}],107:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelize
+ * @typechecks
+ */
+
+var _hyphenPattern = /-(.)/g;
+
+/**
+ * Camelcases a hyphenated string, for example:
+ *
+ *   > camelize('background-color')
+ *   < "backgroundColor"
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelize(string) {
+  return string.replace(_hyphenPattern, function(_, character) {
+    return character.toUpperCase();
+  });
+}
+
+module.exports = camelize;
+
+},{}],108:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelizeStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var camelize = _dereq_(107);
+
+var msPattern = /^-ms-/;
+
+/**
+ * Camelcases a hyphenated CSS property name, for example:
+ *
+ *   > camelizeStyleName('background-color')
+ *   < "backgroundColor"
+ *   > camelizeStyleName('-moz-transition')
+ *   < "MozTransition"
+ *   > camelizeStyleName('-ms-transition')
+ *   < "msTransition"
+ *
+ * As Andi Smith suggests
+ * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
+ * is converted to lowercase `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelizeStyleName(string) {
+  return camelize(string.replace(msPattern, 'ms-'));
+}
+
+module.exports = camelizeStyleName;
+
+},{"107":107}],109:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule containsNode
+ * @typechecks
+ */
+
+var isTextNode = _dereq_(139);
+
+/*jslint bitwise:true */
+
+/**
+ * Checks if a given DOM node contains or is another DOM node.
+ *
+ * @param {?DOMNode} outerNode Outer DOM node.
+ * @param {?DOMNode} innerNode Inner DOM node.
+ * @return {boolean} True if `outerNode` contains or is `innerNode`.
+ */
+function containsNode(outerNode, innerNode) {
+  if (!outerNode || !innerNode) {
+    return false;
+  } else if (outerNode === innerNode) {
+    return true;
+  } else if (isTextNode(outerNode)) {
+    return false;
+  } else if (isTextNode(innerNode)) {
+    return containsNode(outerNode, innerNode.parentNode);
+  } else if (outerNode.contains) {
+    return outerNode.contains(innerNode);
+  } else if (outerNode.compareDocumentPosition) {
+    return !!(outerNode.compareDocumentPosition(innerNode) & 16);
+  } else {
+    return false;
+  }
+}
+
+module.exports = containsNode;
+
+},{"139":139}],110:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createArrayFromMixed
+ * @typechecks
+ */
+
+var toArray = _dereq_(152);
+
+/**
+ * Perform a heuristic test to determine if an object is "array-like".
+ *
+ *   A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
+ *   Joshu replied: "Mu."
+ *
+ * This function determines if its argument has "array nature": it returns
+ * true if the argument is an actual array, an `arguments' object, or an
+ * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
+ *
+ * It will return false for other array-like objects like Filelist.
+ *
+ * @param {*} obj
+ * @return {boolean}
+ */
+function hasArrayNature(obj) {
+  return (
+    // not null/false
+    !!obj &&
+    // arrays are objects, NodeLists are functions in Safari
+    (typeof obj == 'object' || typeof obj == 'function') &&
+    // quacks like an array
+    ('length' in obj) &&
+    // not window
+    !('setInterval' in obj) &&
+    // no DOM node should be considered an array-like
+    // a 'select' element has 'length' and 'item' properties on IE8
+    (typeof obj.nodeType != 'number') &&
+    (
+      // a real array
+      (// HTMLCollection/NodeList
+      (Array.isArray(obj) ||
+      // arguments
+      ('callee' in obj) || 'item' in obj))
+    )
+  );
+}
+
+/**
+ * Ensure that the argument is an array by wrapping it in an array if it is not.
+ * Creates a copy of the argument if it is already an array.
+ *
+ * This is mostly useful idiomatically:
+ *
+ *   var createArrayFromMixed = require('createArrayFromMixed');
+ *
+ *   function takesOneOrMoreThings(things) {
+ *     things = createArrayFromMixed(things);
+ *     ...
+ *   }
+ *
+ * This allows you to treat `things' as an array, but accept scalars in the API.
+ *
+ * If you need to convert an array-like object, like `arguments`, into an array
+ * use toArray instead.
+ *
+ * @param {*} obj
+ * @return {array}
+ */
+function createArrayFromMixed(obj) {
+  if (!hasArrayNature(obj)) {
+    return [obj];
+  } else if (Array.isArray(obj)) {
+    return obj.slice();
+  } else {
+    return toArray(obj);
+  }
+}
+
+module.exports = createArrayFromMixed;
+
+},{"152":152}],111:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createFullPageComponent
+ * @typechecks
+ */
+
+'use strict';
+
+// Defeat circular references by requiring this directly.
+var ReactClass = _dereq_(33);
+var ReactElement = _dereq_(57);
+
+var invariant = _dereq_(135);
+
+/**
+ * Create a component that will throw an exception when unmounted.
+ *
+ * Components like <html> <head> and <body> can't be removed or added
+ * easily in a cross-browser way, however it's valuable to be able to
+ * take advantage of React's reconciliation for styling and <title>
+ * management. So we just document it and throw in dangerous cases.
+ *
+ * @param {string} tag The tag to wrap
+ * @return {function} convenience constructor of new component
+ */
+function createFullPageComponent(tag) {
+  var elementFactory = ReactElement.createFactory(tag);
+
+  var FullPageComponent = ReactClass.createClass({
+    displayName: 'ReactFullPageComponent' + tag,
+
+    componentWillUnmount: function() {
+      ("production" !== "development" ? invariant(
+        false,
+        '%s tried to unmount. Because of cross-browser quirks it is ' +
+        'impossible to unmount some top-level components (eg <html>, <head>, ' +
+        'and <body>) reliably and efficiently. To fix this, have a single ' +
+        'top-level component that never unmounts render these elements.',
+        this.constructor.displayName
+      ) : invariant(false));
+    },
+
+    render: function() {
+      return elementFactory(this.props);
+    }
+  });
+
+  return FullPageComponent;
+}
+
+module.exports = createFullPageComponent;
+
+},{"135":135,"33":33,"57":57}],112:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createNodesFromMarkup
+ * @typechecks
+ */
+
+/*jslint evil: true, sub: true */
+
+var ExecutionEnvironment = _dereq_(21);
+
+var createArrayFromMixed = _dereq_(110);
+var getMarkupWrap = _dereq_(127);
+var invariant = _dereq_(135);
+
+/**
+ * Dummy container used to render all markup.
+ */
+var dummyNode =
+  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Pattern used by `getNodeName`.
+ */
+var nodeNamePattern = /^\s*<(\w+)/;
+
+/**
+ * Extracts the `nodeName` of the first element in a string of markup.
+ *
+ * @param {string} markup String of markup.
+ * @return {?string} Node name of the supplied markup.
+ */
+function getNodeName(markup) {
+  var nodeNameMatch = markup.match(nodeNamePattern);
+  return nodeNameMatch && nodeNameMatch[1].toLowerCase();
+}
+
+/**
+ * Creates an array containing the nodes rendered from the supplied markup. The
+ * optionally supplied `handleScript` function will be invoked once for each
+ * <script> element that is rendered. If no `handleScript` function is supplied,
+ * an exception is thrown if any <script> elements are rendered.
+ *
+ * @param {string} markup A string of valid HTML markup.
+ * @param {?function} handleScript Invoked once for each rendered <script>.
+ * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
+ */
+function createNodesFromMarkup(markup, handleScript) {
+  var node = dummyNode;
+  ("production" !== "development" ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode));
+  var nodeName = getNodeName(markup);
+
+  var wrap = nodeName && getMarkupWrap(nodeName);
+  if (wrap) {
+    node.innerHTML = wrap[1] + markup + wrap[2];
+
+    var wrapDepth = wrap[0];
+    while (wrapDepth--) {
+      node = node.lastChild;
+    }
+  } else {
+    node.innerHTML = markup;
+  }
+
+  var scripts = node.getElementsByTagName('script');
+  if (scripts.length) {
+    ("production" !== "development" ? invariant(
+      handleScript,
+      'createNodesFromMarkup(...): Unexpected <script> element rendered.'
+    ) : invariant(handleScript));
+    createArrayFromMixed(scripts).forEach(handleScript);
+  }
+
+  var nodes = createArrayFromMixed(node.childNodes);
+  while (node.lastChild) {
+    node.removeChild(node.lastChild);
+  }
+  return nodes;
+}
+
+module.exports = createNodesFromMarkup;
+
+},{"110":110,"127":127,"135":135,"21":21}],113:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule dangerousStyleValue
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CSSProperty = _dereq_(4);
+
+var isUnitlessNumber = CSSProperty.isUnitlessNumber;
+
+/**
+ * Convert a value into the proper css writable value. The style name `name`
+ * should be logical (no hyphens), as specified
+ * in `CSSProperty.isUnitlessNumber`.
+ *
+ * @param {string} name CSS property name such as `topMargin`.
+ * @param {*} value CSS property value such as `10px`.
+ * @return {string} Normalized style value with dimensions applied.
+ */
+function dangerousStyleValue(name, value) {
+  // Note that we've removed escapeTextForBrowser() calls here since the
+  // whole string will be escaped when the attribute is injected into
+  // the markup. If you provide unsafe user data here they can inject
+  // arbitrary CSS which may be problematic (I couldn't repro this):
+  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
+  // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
+  // This is not an XSS hole but instead a potential CSS injection issue
+  // which has lead to a greater discussion about how we're going to
+  // trust URLs moving forward. See #2115901
+
+  var isEmpty = value == null || typeof value === 'boolean' || value === '';
+  if (isEmpty) {
+    return '';
+  }
+
+  var isNonNumeric = isNaN(value);
+  if (isNonNumeric || value === 0 ||
+      isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
+    return '' + value; // cast to string
+  }
+
+  if (typeof value === 'string') {
+    value = value.trim();
+  }
+  return value + 'px';
+}
+
+module.exports = dangerousStyleValue;
+
+},{"4":4}],114:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyFunction
+ */
+
+function makeEmptyFunction(arg) {
+  return function() {
+    return arg;
+  };
+}
+
+/**
+ * This function accepts and discards inputs; it has no side effects. This is
+ * primarily useful idiomatically for overridable function endpoints which
+ * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
+ */
+function emptyFunction() {}
+
+emptyFunction.thatReturns = makeEmptyFunction;
+emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
+emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
+emptyFunction.thatReturnsNull = makeEmptyFunction(null);
+emptyFunction.thatReturnsThis = function() { return this; };
+emptyFunction.thatReturnsArgument = function(arg) { return arg; };
+
+module.exports = emptyFunction;
+
+},{}],115:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyObject
+ */
+
+"use strict";
+
+var emptyObject = {};
+
+if ("production" !== "development") {
+  Object.freeze(emptyObject);
+}
+
+module.exports = emptyObject;
+
+},{}],116:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule escapeTextContentForBrowser
+ */
+
+'use strict';
+
+var ESCAPE_LOOKUP = {
+  '&': '&',
+  '>': '>',
+  '<': '<',
+  '"': '"',
+  '\'': '&#x27;'
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+  return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escapeTextContentForBrowser(text) {
+  return ('' + text).replace(ESCAPE_REGEX, escaper);
+}
+
+module.exports = escapeTextContentForBrowser;
+
+},{}],117:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule findDOMNode
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactCurrentOwner = _dereq_(39);
+var ReactInstanceMap = _dereq_(67);
+var ReactMount = _dereq_(70);
+
+var invariant = _dereq_(135);
+var isNode = _dereq_(137);
+var warning = _dereq_(154);
+
+/**
+ * Returns the DOM node rendered by this element.
+ *
+ * @param {ReactComponent|DOMElement} componentOrElement
+ * @return {DOMElement} The root node of this element.
+ */
+function findDOMNode(componentOrElement) {
+  if ("production" !== "development") {
+    var owner = ReactCurrentOwner.current;
+    if (owner !== null) {
+      ("production" !== "development" ? warning(
+        owner._warnedAboutRefsInRender,
+        '%s is accessing getDOMNode or findDOMNode inside its render(). ' +
+        'render() should be a pure function of props and state. It should ' +
+        'never access something that requires stale data from the previous ' +
+        'render, such as refs. Move this logic to componentDidMount and ' +
+        'componentDidUpdate instead.',
+        owner.getName() || 'A component'
+      ) : null);
+      owner._warnedAboutRefsInRender = true;
+    }
+  }
+  if (componentOrElement == null) {
+    return null;
+  }
+  if (isNode(componentOrElement)) {
+    return componentOrElement;
+  }
+  if (ReactInstanceMap.has(componentOrElement)) {
+    return ReactMount.getNodeFromInstance(componentOrElement);
+  }
+  ("production" !== "development" ? invariant(
+    componentOrElement.render == null ||
+    typeof componentOrElement.render !== 'function',
+    'Component (with keys: %s) contains `render` method ' +
+    'but is not mounted in the DOM',
+    Object.keys(componentOrElement)
+  ) : invariant(componentOrElement.render == null ||
+  typeof componentOrElement.render !== 'function'));
+  ("production" !== "development" ? invariant(
+    false,
+    'Element appears to be neither ReactComponent nor DOMNode (keys: %s)',
+    Object.keys(componentOrElement)
+  ) : invariant(false));
+}
+
+module.exports = findDOMNode;
+
+},{"135":135,"137":137,"154":154,"39":39,"67":67,"70":70}],118:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule flattenChildren
+ */
+
+'use strict';
+
+var traverseAllChildren = _dereq_(153);
+var warning = _dereq_(154);
+
+/**
+ * @param {function} traverseContext Context passed through traversal.
+ * @param {?ReactComponent} child React child component.
+ * @param {!string} name String name of key path to child.
+ */
+function flattenSingleChildIntoContext(traverseContext, child, name) {
+  // We found a component instance.
+  var result = traverseContext;
+  var keyUnique = !result.hasOwnProperty(name);
+  if ("production" !== "development") {
+    ("production" !== "development" ? warning(
+      keyUnique,
+      'flattenChildren(...): Encountered two children with the same key, ' +
+      '`%s`. Child keys must be unique; when two children share a key, only ' +
+      'the first child will be used.',
+      name
+    ) : null);
+  }
+  if (keyUnique && child != null) {
+    result[name] = child;
+  }
+}
+
+/**
+ * Flattens children that are typically specified as `props.children`. Any null
+ * children will not be included in the resulting object.
+ * @return {!object} flattened children keyed by name.
+ */
+function flattenChildren(children) {
+  if (children == null) {
+    return children;
+  }
+  var result = {};
+  traverseAllChildren(children, flattenSingleChildIntoContext, result);
+  return result;
+}
+
+module.exports = flattenChildren;
+
+},{"153":153,"154":154}],119:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule focusNode
+ */
+
+"use strict";
+
+/**
+ * @param {DOMElement} node input/textarea to focus
+ */
+function focusNode(node) {
+  // IE8 can throw "Can't move focus to the control because it is invisible,
+  // not enabled, or of a type that does not accept the focus." for all kinds of
+  // reasons that are too expensive and fragile to test.
+  try {
+    node.focus();
+  } catch(e) {
+  }
+}
+
+module.exports = focusNode;
+
+},{}],120:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule forEachAccumulated
+ */
+
+'use strict';
+
+/**
+ * @param {array} an "accumulation" of items which is either an Array or
+ * a single item. Useful when paired with the `accumulate` module. This is a
+ * simple utility that allows us to reason about a collection of items, but
+ * handling the case when there is exactly one item (and we do not need to
+ * allocate an array).
+ */
+var forEachAccumulated = function(arr, cb, scope) {
+  if (Array.isArray(arr)) {
+    arr.forEach(cb, scope);
+  } else if (arr) {
+    cb.call(scope, arr);
+  }
+};
+
+module.exports = forEachAccumulated;
+
+},{}],121:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getActiveElement
+ * @typechecks
+ */
+
+/**
+ * Same as document.activeElement but wraps in a try-catch block. In IE it is
+ * not safe to call document.activeElement if there is nothing focused.
+ *
+ * The activeElement will be null only if the document body is not yet defined.
+ */
+function getActiveElement() /*?DOMElement*/ {
+  try {
+    return document.activeElement || document.body;
+  } catch (e) {
+    return document.body;
+  }
+}
+
+module.exports = getActiveElement;
+
+},{}],122:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventCharCode
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * `charCode` represents the actual "character code" and is safe to use with
+ * `String.fromCharCode`. As such, only keys that correspond to printable
+ * characters produce a valid `charCode`, the only exception to this is Enter.
+ * The Tab-key is considered non-printable and does not have a `charCode`,
+ * presumably because it does not produce a tab-character in browsers.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `charCode` property.
+ */
+function getEventCharCode(nativeEvent) {
+  var charCode;
+  var keyCode = nativeEvent.keyCode;
+
+  if ('charCode' in nativeEvent) {
+    charCode = nativeEvent.charCode;
+
+    // FF does not set `charCode` for the Enter-key, check against `keyCode`.
+    if (charCode === 0 && keyCode === 13) {
+      charCode = 13;
+    }
+  } else {
+    // IE8 does not implement `charCode`, but `keyCode` has the correct value.
+    charCode = keyCode;
+  }
+
+  // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
+  // Must not discard the (non-)printable Enter-key.
+  if (charCode >= 32 || charCode === 13) {
+    return charCode;
+  }
+
+  return 0;
+}
+
+module.exports = getEventCharCode;
+
+},{}],123:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventKey
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var getEventCharCode = _dereq_(122);
+
+/**
+ * Normalization of deprecated HTML5 `key` values
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var normalizeKey = {
+  'Esc': 'Escape',
+  'Spacebar': ' ',
+  'Left': 'ArrowLeft',
+  'Up': 'ArrowUp',
+  'Right': 'ArrowRight',
+  'Down': 'ArrowDown',
+  'Del': 'Delete',
+  'Win': 'OS',
+  'Menu': 'ContextMenu',
+  'Apps': 'ContextMenu',
+  'Scroll': 'ScrollLock',
+  'MozPrintableKey': 'Unidentified'
+};
+
+/**
+ * Translation from legacy `keyCode` to HTML5 `key`
+ * Only special keys supported, all others depend on keyboard layout or browser
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var translateToKey = {
+  8: 'Backspace',
+  9: 'Tab',
+  12: 'Clear',
+  13: 'Enter',
+  16: 'Shift',
+  17: 'Control',
+  18: 'Alt',
+  19: 'Pause',
+  20: 'CapsLock',
+  27: 'Escape',
+  32: ' ',
+  33: 'PageUp',
+  34: 'PageDown',
+  35: 'End',
+  36: 'Home',
+  37: 'ArrowLeft',
+  38: 'ArrowUp',
+  39: 'ArrowRight',
+  40: 'ArrowDown',
+  45: 'Insert',
+  46: 'Delete',
+  112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6',
+  118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
+  144: 'NumLock',
+  145: 'ScrollLock',
+  224: 'Meta'
+};
+
+/**
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `key` property.
+ */
+function getEventKey(nativeEvent) {
+  if (nativeEvent.key) {
+    // Normalize inconsistent values reported by browsers due to
+    // implementations of a working draft specification.
+
+    // FireFox implements `key` but returns `MozPrintableKey` for all
+    // printable characters (normalized to `Unidentified`), ignore it.
+    var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
+    if (key !== 'Unidentified') {
+      return key;
+    }
+  }
+
+  // Browser does not implement `key`, polyfill as much of it as we can.
+  if (nativeEvent.type === 'keypress') {
+    var charCode = getEventCharCode(nativeEvent);
+
+    // The enter-key is technically both printable and non-printable and can
+    // thus be captured by `keypress`, no other non-printable key should.
+    return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
+  }
+  if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
+    // While user keyboard layout determines the actual meaning of each
+    // `keyCode` value, almost all function keys have a universal value.
+    return translateToKey[nativeEvent.keyCode] || 'Unidentified';
+  }
+  return '';
+}
+
+module.exports = getEventKey;
+
+},{"122":122}],124:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventModifierState
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Translation from modifier key to the associated property in the event.
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
+ */
+
+var modifierKeyToProp = {
+  'Alt': 'altKey',
+  'Control': 'ctrlKey',
+  'Meta': 'metaKey',
+  'Shift': 'shiftKey'
+};
+
+// IE8 does not implement getModifierState so we simply map it to the only
+// modifier keys exposed by the event itself, does not support Lock-keys.
+// Currently, all major browsers except Chrome seems to support Lock-keys.
+function modifierStateGetter(keyArg) {
+  /*jshint validthis:true */
+  var syntheticEvent = this;
+  var nativeEvent = syntheticEvent.nativeEvent;
+  if (nativeEvent.getModifierState) {
+    return nativeEvent.getModifierState(keyArg);
+  }
+  var keyProp = modifierKeyToProp[keyArg];
+  return keyProp ? !!nativeEvent[keyProp] : false;
+}
+
+function getEventModifierState(nativeEvent) {
+  return modifierStateGetter;
+}
+
+module.exports = getEventModifierState;
+
+},{}],125:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventTarget
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Gets the target node from a native browser event by accounting for
+ * inconsistencies in browser DOM APIs.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {DOMEventTarget} Target node.
+ */
+function getEventTarget(nativeEvent) {
+  var target = nativeEvent.target || nativeEvent.srcElement || window;
+  // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
+  // @see http://www.quirksmode.org/js/events_properties.html
+  return target.nodeType === 3 ? target.parentNode : target;
+}
+
+module.exports = getEventTarget;
+
+},{}],126:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getIteratorFn
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/* global Symbol */
+var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
+var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
+
+/**
+ * Returns the iterator method function contained on the iterable object.
+ *
+ * Be sure to invoke the function with the iterable as context:
+ *
+ *     var iteratorFn = getIteratorFn(myIterable);
+ *     if (iteratorFn) {
+ *       var iterator = iteratorFn.call(myIterable);
+ *       ...
+ *     }
+ *
+ * @param {?object} maybeIterable
+ * @return {?function}
+ */
+function getIteratorFn(maybeIterable) {
+  var iteratorFn = maybeIterable && (
+    (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL])
+  );
+  if (typeof iteratorFn === 'function') {
+    return iteratorFn;
+  }
+}
+
+module.exports = getIteratorFn;
+
+},{}],127:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getMarkupWrap
+ */
+
+var ExecutionEnvironment = _dereq_(21);
+
+var invariant = _dereq_(135);
+
+/**
+ * Dummy container used to detect which wraps are necessary.
+ */
+var dummyNode =
+  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Some browsers cannot use `innerHTML` to render certain elements standalone,
+ * so we wrap them, render the wrapped nodes, then extract the desired node.
+ *
+ * In IE8, certain elements cannot render alone, so wrap all elements ('*').
+ */
+var shouldWrap = {
+  // Force wrapping for SVG elements because if they get created inside a <div>,
+  // they will be initialized in the wrong namespace (and will not display).
+  'circle': true,
+  'defs': true,
+  'ellipse': true,
+  'g': true,
+  'line': true,
+  'linearGradient': true,
+  'path': true,
+  'polygon': true,
+  'polyline': true,
+  'radialGradient': true,
+  'rect': true,
+  'stop': true,
+  'text': true
+};
+
+var selectWrap = [1, '<select multiple="true">', '</select>'];
+var tableWrap = [1, '<table>', '</table>'];
+var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
+
+var svgWrap = [1, '<svg>', '</svg>'];
+
+var markupWrap = {
+  '*': [1, '?<div>', '</div>'],
+
+  'area': [1, '<map>', '</map>'],
+  'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+  'legend': [1, '<fieldset>', '</fieldset>'],
+  'param': [1, '<object>', '</object>'],
+  'tr': [2, '<table><tbody>', '</tbody></table>'],
+
+  'optgroup': selectWrap,
+  'option': selectWrap,
+
+  'caption': tableWrap,
+  'colgroup': tableWrap,
+  'tbody': tableWrap,
+  'tfoot': tableWrap,
+  'thead': tableWrap,
+
+  'td': trWrap,
+  'th': trWrap,
+
+  'circle': svgWrap,
+  'defs': svgWrap,
+  'ellipse': svgWrap,
+  'g': svgWrap,
+  'line': svgWrap,
+  'linearGradient': svgWrap,
+  'path': svgWrap,
+  'polygon': svgWrap,
+  'polyline': svgWrap,
+  'radialGradient': svgWrap,
+  'rect': svgWrap,
+  'stop': svgWrap,
+  'text': svgWrap
+};
+
+/**
+ * Gets the markup wrap configuration for the supplied `nodeName`.
+ *
+ * NOTE: This lazily detects which wraps are necessary for the current browser.
+ *
+ * @param {string} nodeName Lowercase `nodeName`.
+ * @return {?array} Markup wrap configuration, if applicable.
+ */
+function getMarkupWrap(nodeName) {
+  ("production" !== "development" ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode));
+  if (!markupWrap.hasOwnProperty(nodeName)) {
+    nodeName = '*';
+  }
+  if (!shouldWrap.hasOwnProperty(nodeName)) {
+    if (nodeName === '*') {
+      dummyNode.innerHTML = '<link />';
+    } else {
+      dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
+    }
+    shouldWrap[nodeName] = !dummyNode.firstChild;
+  }
+  return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
+}
+
+
+module.exports = getMarkupWrap;
+
+},{"135":135,"21":21}],128:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getNodeForCharacterOffset
+ */
+
+'use strict';
+
+/**
+ * Given any node return the first leaf node without children.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {DOMElement|DOMTextNode}
+ */
+function getLeafNode(node) {
+  while (node && node.firstChild) {
+    node = node.firstChild;
+  }
+  return node;
+}
+
+/**
+ * Get the next sibling within a container. This will walk up the
+ * DOM if a node's siblings have been exhausted.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {?DOMElement|DOMTextNode}
+ */
+function getSiblingNode(node) {
+  while (node) {
+    if (node.nextSibling) {
+      return node.nextSibling;
+    }
+    node = node.parentNode;
+  }
+}
+
+/**
+ * Get object describing the nodes which contain characters at offset.
+ *
+ * @param {DOMElement|DOMTextNode} root
+ * @param {number} offset
+ * @return {?object}
+ */
+function getNodeForCharacterOffset(root, offset) {
+  var node = getLeafNode(root);
+  var nodeStart = 0;
+  var nodeEnd = 0;
+
+  while (node) {
+    if (node.nodeType === 3) {
+      nodeEnd = nodeStart + node.textContent.length;
+
+      if (nodeStart <= offset && nodeEnd >= offset) {
+        return {
+          node: node,
+          offset: offset - nodeStart
+        };
+      }
+
+      nodeStart = nodeEnd;
+    }
+
+    node = getLeafNode(getSiblingNode(node));
+  }
+}
+
+module.exports = getNodeForCharacterOffset;
+
+},{}],129:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getReactRootElementInContainer
+ */
+
+'use strict';
+
+var DOC_NODE_TYPE = 9;
+
+/**
+ * @param {DOMElement|DOMDocument} container DOM element that may contain
+ *                                           a React component
+ * @return {?*} DOM element that may have the reactRoot ID, or null.
+ */
+function getReactRootElementInContainer(container) {
+  if (!container) {
+    return null;
+  }
+
+  if (container.nodeType === DOC_NODE_TYPE) {
+    return container.documentElement;
+  } else {
+    return container.firstChild;
+  }
+}
+
+module.exports = getReactRootElementInContainer;
+
+},{}],130:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getTextContentAccessor
+ */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+
+var contentKey = null;
+
+/**
+ * Gets the key used to access text content on a DOM node.
+ *
+ * @return {?string} Key used to access text content.
+ * @internal
+ */
+function getTextContentAccessor() {
+  if (!contentKey && ExecutionEnvironment.canUseDOM) {
+    // Prefer textContent to innerText because many browsers support both but
+    // SVG <text> elements don't support innerText even when <div> does.
+    contentKey = 'textContent' in document.documentElement ?
+      'textContent' :
+      'innerText';
+  }
+  return contentKey;
+}
+
+module.exports = getTextContentAccessor;
+
+},{"21":21}],131:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getUnboundedScrollPosition
+ * @typechecks
+ */
+
+"use strict";
+
+/**
+ * Gets the scroll position of the supplied element or window.
+ *
+ * The return values are unbounded, unlike `getScrollPosition`. This means they
+ * may be negative or exceed the element boundaries (which is possible using
+ * inertial scrolling).
+ *
+ * @param {DOMWindow|DOMElement} scrollable
+ * @return {object} Map with `x` and `y` keys.
+ */
+function getUnboundedScrollPosition(scrollable) {
+  if (scrollable === window) {
+    return {
+      x: window.pageXOffset || document.documentElement.scrollLeft,
+      y: window.pageYOffset || document.documentElement.scrollTop
+    };
+  }
+  return {
+    x: scrollable.scrollLeft,
+    y: scrollable.scrollTop
+  };
+}
+
+module.exports = getUnboundedScrollPosition;
+
+},{}],132:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenate
+ * @typechecks
+ */
+
+var _uppercasePattern = /([A-Z])/g;
+
+/**
+ * Hyphenates a camelcased string, for example:
+ *
+ *   > hyphenate('backgroundColor')
+ *   < "background-color"
+ *
+ * For CSS style names, use `hyphenateStyleName` instead which works properly
+ * with all vendor prefixes, including `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenate(string) {
+  return string.replace(_uppercasePattern, '-$1').toLowerCase();
+}
+
+module.exports = hyphenate;
+
+},{}],133:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenateStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var hyphenate = _dereq_(132);
+
+var msPattern = /^ms-/;
+
+/**
+ * Hyphenates a camelcased CSS property name, for example:
+ *
+ *   > hyphenateStyleName('backgroundColor')
+ *   < "background-color"
+ *   > hyphenateStyleName('MozTransition')
+ *   < "-moz-transition"
+ *   > hyphenateStyleName('msTransition')
+ *   < "-ms-transition"
+ *
+ * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
+ * is converted to `-ms-`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenateStyleName(string) {
+  return hyphenate(string).replace(msPattern, '-ms-');
+}
+
+module.exports = hyphenateStyleName;
+
+},{"132":132}],134:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule instantiateReactComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactCompositeComponent = _dereq_(37);
+var ReactEmptyComponent = _dereq_(59);
+var ReactNativeComponent = _dereq_(73);
+
+var assign = _dereq_(27);
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+// To avoid a cyclic dependency, we create the final class in this module
+var ReactCompositeComponentWrapper = function() { };
+assign(
+  ReactCompositeComponentWrapper.prototype,
+  ReactCompositeComponent.Mixin,
+  {
+    _instantiateReactComponent: instantiateReactComponent
+  }
+);
+
+/**
+ * Check if the type reference is a known internal type. I.e. not a user
+ * provided composite type.
+ *
+ * @param {function} type
+ * @return {boolean} Returns true if this is a valid internal type.
+ */
+function isInternalComponentType(type) {
+  return (
+    typeof type === 'function' &&
+    typeof type.prototype.mountComponent === 'function' &&
+    typeof type.prototype.receiveComponent === 'function'
+  );
+}
+
+/**
+ * Given a ReactNode, create an instance that will actually be mounted.
+ *
+ * @param {ReactNode} node
+ * @param {*} parentCompositeType The composite type that resolved this.
+ * @return {object} A new instance of the element's constructor.
+ * @protected
+ */
+function instantiateReactComponent(node, parentCompositeType) {
+  var instance;
+
+  if (node === null || node === false) {
+    node = ReactEmptyComponent.emptyElement;
+  }
+
+  if (typeof node === 'object') {
+    var element = node;
+    if ("production" !== "development") {
+      ("production" !== "development" ? warning(
+        element && (typeof element.type === 'function' ||
+                    typeof element.type === 'string'),
+        'Only functions or strings can be mounted as React components.'
+      ) : null);
+    }
+
+    // Special case string values
+    if (parentCompositeType === element.type &&
+        typeof element.type === 'string') {
+      // Avoid recursion if the wrapper renders itself.
+      instance = ReactNativeComponent.createInternalComponent(element);
+      // All native components are currently wrapped in a composite so we're
+      // safe to assume that this is what we should instantiate.
+    } else if (isInternalComponentType(element.type)) {
+      // This is temporarily available for custom components that are not string
+      // represenations. I.e. ART. Once those are updated to use the string
+      // representation, we can drop this code path.
+      instance = new element.type(element);
+    } else {
+      instance = new ReactCompositeComponentWrapper();
+    }
+  } else if (typeof node === 'string' || typeof node === 'number') {
+    instance = ReactNativeComponent.createInstanceForText(node);
+  } else {
+    ("production" !== "development" ? invariant(
+      false,
+      'Encountered invalid React node of type %s',
+      typeof node
+    ) : invariant(false));
+  }
+
+  if ("production" !== "development") {
+    ("production" !== "development" ? warning(
+      typeof instance.construct === 'function' &&
+      typeof instance.mountComponent === 'function' &&
+      typeof instance.receiveComponent === 'function' &&
+      typeof instance.unmountComponent === 'function',
+      'Only React Components can be mounted.'
+    ) : null);
+  }
+
+  // Sets up the instance. This can probably just move into the constructor now.
+  instance.construct(node);
+
+  // These two fields are used by the DOM and ART diffing algorithms
+  // respectively. Instead of using expandos on components, we should be
+  // storing the state needed by the diffing algorithms elsewhere.
+  instance._mountIndex = 0;
+  instance._mountImage = null;
+
+  if ("production" !== "development") {
+    instance._isOwnerNecessary = false;
+    instance._warnedAboutRefsInRender = false;
+  }
+
+  // Internal instances should fully constructed at this point, so they should
+  // not get any new fields added to them at this point.
+  if ("production" !== "development") {
+    if (Object.preventExtensions) {
+      Object.preventExtensions(instance);
+    }
+  }
+
+  return instance;
+}
+
+module.exports = instantiateReactComponent;
+
+},{"135":135,"154":154,"27":27,"37":37,"59":59,"73":73}],135:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule invariant
+ */
+
+"use strict";
+
+/**
+ * Use invariant() to assert state which your program assumes to be true.
+ *
+ * Provide sprintf-style format (only %s is supported) and arguments
+ * to provide information about what broke and what you were
+ * expecting.
+ *
+ * The invariant message will be stripped in production, but the invariant
+ * will remain to ensure logic does not differ in production.
+ */
+
+var invariant = function(condition, format, a, b, c, d, e, f) {
+  if ("production" !== "development") {
+    if (format === undefined) {
+      throw new Error('invariant requires an error message argument');
+    }
+  }
+
+  if (!condition) {
+    var error;
+    if (format === undefined) {
+      error = new Error(
+        'Minified exception occurred; use the non-minified dev environment ' +
+        'for the full error message and additional helpful warnings.'
+      );
+    } else {
+      var args = [a, b, c, d, e, f];
+      var argIndex = 0;
+      error = new Error(
+        'Invariant Violation: ' +
+        format.replace(/%s/g, function() { return args[argIndex++]; })
+      );
+    }
+
+    error.framesToPop = 1; // we don't care about invariant's own frame
+    throw error;
+  }
+};
+
+module.exports = invariant;
+
+},{}],136:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isEventSupported
+ */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+
+var useHasFeature;
+if (ExecutionEnvironment.canUseDOM) {
+  useHasFeature =
+    document.implementation &&
+    document.implementation.hasFeature &&
+    // always returns true in newer browsers as per the standard.
+    // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
+    document.implementation.hasFeature('', '') !== true;
+}
+
+/**
+ * Checks if an event is supported in the current execution environment.
+ *
+ * NOTE: This will not work correctly for non-generic events such as `change`,
+ * `reset`, `load`, `error`, and `select`.
+ *
+ * Borrows from Modernizr.
+ *
+ * @param {string} eventNameSuffix Event name, e.g. "click".
+ * @param {?boolean} capture Check if the capture phase is supported.
+ * @return {boolean} True if the event is supported.
+ * @internal
+ * @license Modernizr 3.0.0pre (Custom Build) | MIT
+ */
+function isEventSupported(eventNameSuffix, capture) {
+  if (!ExecutionEnvironment.canUseDOM ||
+      capture && !('addEventListener' in document)) {
+    return false;
+  }
+
+  var eventName = 'on' + eventNameSuffix;
+  var isSupported = eventName in document;
+
+  if (!isSupported) {
+    var element = document.createElement('div');
+    element.setAttribute(eventName, 'return;');
+    isSupported = typeof element[eventName] === 'function';
+  }
+
+  if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
+    // This is the only way to test support for the `wheel` event in IE9+.
+    isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
+  }
+
+  return isSupported;
+}
+
+module.exports = isEventSupported;
+
+},{"21":21}],137:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isNode
+ * @typechecks
+ */
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM node.
+ */
+function isNode(object) {
+  return !!(object && (
+    ((typeof Node === 'function' ? object instanceof Node : typeof object === 'object' &&
+    typeof object.nodeType === 'number' &&
+    typeof object.nodeName === 'string'))
+  ));
+}
+
+module.exports = isNode;
+
+},{}],138:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextInputElement
+ */
+
+'use strict';
+
+/**
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+ */
+var supportedInputTypes = {
+  'color': true,
+  'date': true,
+  'datetime': true,
+  'datetime-local': true,
+  'email': true,
+  'month': true,
+  'number': true,
+  'password': true,
+  'range': true,
+  'search': true,
+  'tel': true,
+  'text': true,
+  'time': true,
+  'url': true,
+  'week': true
+};
+
+function isTextInputElement(elem) {
+  return elem && (
+    (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type] || elem.nodeName === 'TEXTAREA')
+  );
+}
+
+module.exports = isTextInputElement;
+
+},{}],139:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextNode
+ * @typechecks
+ */
+
+var isNode = _dereq_(137);
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM text node.
+ */
+function isTextNode(object) {
+  return isNode(object) && object.nodeType == 3;
+}
+
+module.exports = isTextNode;
+
+},{"137":137}],140:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyMirror
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var invariant = _dereq_(135);
+
+/**
+ * Constructs an enumeration with keys equal to their value.
+ *
+ * For example:
+ *
+ *   var COLORS = keyMirror({blue: null, red: null});
+ *   var myColor = COLORS.blue;
+ *   var isColorValid = !!COLORS[myColor];
+ *
+ * The last line could not be performed if the values of the generated enum were
+ * not equal to their keys.
+ *
+ *   Input:  {key1: val1, key2: val2}
+ *   Output: {key1: key1, key2: key2}
+ *
+ * @param {object} obj
+ * @return {object}
+ */
+var keyMirror = function(obj) {
+  var ret = {};
+  var key;
+  ("production" !== "development" ? invariant(
+    obj instanceof Object && !Array.isArray(obj),
+    'keyMirror(...): Argument must be an object.'
+  ) : invariant(obj instanceof Object && !Array.isArray(obj)));
+  for (key in obj) {
+    if (!obj.hasOwnProperty(key)) {
+      continue;
+    }
+    ret[key] = key;
+  }
+  return ret;
+};
+
+module.exports = keyMirror;
+
+},{"135":135}],141:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyOf
+ */
+
+/**
+ * Allows extraction of a minified key. Let's the build system minify keys
+ * without loosing the ability to dynamically use key strings as values
+ * themselves. Pass in an object with a single key/val pair and it will return
+ * you the string key of that single record. Suppose you want to grab the
+ * value for a key 'className' inside of an object. Key/val minification may
+ * have aliased that key to be 'xa12'. keyOf({className: null}) will return
+ * 'xa12' in that case. Resolve keys you want to use once at startup time, then
+ * reuse those resolutions.
+ */
+var keyOf = function(oneKeyObj) {
+  var key;
+  for (key in oneKeyObj) {
+    if (!oneKeyObj.hasOwnProperty(key)) {
+      continue;
+    }
+    return key;
+  }
+  return null;
+};
+
+
+module.exports = keyOf;
+
+},{}],142:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule mapObject
+ */
+
+'use strict';
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Executes the provided `callback` once for each enumerable own property in the
+ * object and constructs a new object from the results. The `callback` is
+ * invoked with three arguments:
+ *
+ *  - the property value
+ *  - the property name
+ *  - the object being traversed
+ *
+ * Properties that are added after the call to `mapObject` will not be visited
+ * by `callback`. If the values of existing properties are changed, the value
+ * passed to `callback` will be the value at the time `mapObject` visits them.
+ * Properties that are deleted before being visited are not visited.
+ *
+ * @grep function objectMap()
+ * @grep function objMap()
+ *
+ * @param {?object} object
+ * @param {function} callback
+ * @param {*} context
+ * @return {?object}
+ */
+function mapObject(object, callback, context) {
+  if (!object) {
+    return null;
+  }
+  var result = {};
+  for (var name in object) {
+    if (hasOwnProperty.call(object, name)) {
+      result[name] = callback.call(context, object[name], name, object);
+    }
+  }
+  return result;
+}
+
+module.exports = mapObject;
+
+},{}],143:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule memoizeStringOnly
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Memoizes the return value of a function that accepts one string argument.
+ *
+ * @param {function} callback
+ * @return {function}
+ */
+function memoizeStringOnly(callback) {
+  var cache = {};
+  return function(string) {
+    if (!cache.hasOwnProperty(string)) {
+      cache[string] = callback.call(this, string);
+    }
+    return cache[string];
+  };
+}
+
+module.exports = memoizeStringOnly;
+
+},{}],144:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule onlyChild
+ */
+'use strict';
+
+var ReactElement = _dereq_(57);
+
+var invariant = _dereq_(135);
+
+/**
+ * Returns the first child in a collection of children and verifies that there
+ * is only one child in the collection. The current implementation of this
+ * function assumes that a single child gets passed without a wrapper, but the
+ * purpose of this helper function is to abstract away the particular structure
+ * of children.
+ *
+ * @param {?object} children Child collection structure.
+ * @return {ReactComponent} The first and only `ReactComponent` contained in the
+ * structure.
+ */
+function onlyChild(children) {
+  ("production" !== "development" ? invariant(
+    ReactElement.isValidElement(children),
+    'onlyChild must be passed a children with exactly one child.'
+  ) : invariant(ReactElement.isValidElement(children)));
+  return children;
+}
+
+module.exports = onlyChild;
+
+},{"135":135,"57":57}],145:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performance
+ * @typechecks
+ */
+
+"use strict";
+
+var ExecutionEnvironment = _dereq_(21);
+
+var performance;
+
+if (ExecutionEnvironment.canUseDOM) {
+  performance =
+    window.performance ||
+    window.msPerformance ||
+    window.webkitPerformance;
+}
+
+module.exports = performance || {};
+
+},{"21":21}],146:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performanceNow
+ * @typechecks
+ */
+
+var performance = _dereq_(145);
+
+/**
+ * Detect if we can use `window.performance.now()` and gracefully fallback to
+ * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
+ * because of Facebook's testing infrastructure.
+ */
+if (!performance || !performance.now) {
+  performance = Date;
+}
+
+var performanceNow = performance.now.bind(performance);
+
+module.exports = performanceNow;
+
+},{"145":145}],147:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule quoteAttributeValueForBrowser
+ */
+
+'use strict';
+
+var escapeTextContentForBrowser = _dereq_(116);
+
+/**
+ * Escapes attribute value to prevent scripting attacks.
+ *
+ * @param {*} value Value to escape.
+ * @return {string} An escaped string.
+ */
+function quoteAttributeValueForBrowser(value) {
+  return '"' + escapeTextContentForBrowser(value) + '"';
+}
+
+module.exports = quoteAttributeValueForBrowser;
+
+},{"116":116}],148:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule setInnerHTML
+ */
+
+/* globals MSApp */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+
+var WHITESPACE_TEST = /^[ \r\n\t\f]/;
+var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
+
+/**
+ * Set the innerHTML property of a node, ensuring that whitespace is preserved
+ * even in IE8.
+ *
+ * @param {DOMElement} node
+ * @param {string} html
+ * @internal
+ */
+var setInnerHTML = function(node, html) {
+  node.innerHTML = html;
+};
+
+// Win8 apps: Allow all html to be inserted
+if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
+  setInnerHTML = function(node, html) {
+    MSApp.execUnsafeLocalFunction(function() {
+      node.innerHTML = html;
+    });
+  };
+}
+
+if (ExecutionEnvironment.canUseDOM) {
+  // IE8: When updating a just created node with innerHTML only leading
+  // whitespace is removed. When updating an existing node with innerHTML
+  // whitespace in root TextNodes is also collapsed.
+  // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
+
+  // Feature detection; only IE8 is known to behave improperly like this.
+  var testElement = document.createElement('div');
+  testElement.innerHTML = ' ';
+  if (testElement.innerHTML === '') {
+    setInnerHTML = function(node, html) {
+      // Magic theory: IE8 supposedly differentiates between added and updated
+      // nodes when processing innerHTML, innerHTML on updated nodes suffers
+      // from worse whitespace behavior. Re-adding a node like this triggers
+      // the initial and more favorable whitespace behavior.
+      // TODO: What to do on a detached node?
+      if (node.parentNode) {
+        node.parentNode.replaceChild(node, node);
+      }
+
+      // We also implement a workaround for non-visible tags disappearing into
+      // thin air on IE8, this only happens if there is no visible text
+      // in-front of the non-visible tags. Piggyback on the whitespace fix
+      // and simply check if any non-visible tags appear in the source.
+      if (WHITESPACE_TEST.test(html) ||
+          html[0] === '<' && NONVISIBLE_TEST.test(html)) {
+        // Recover leading whitespace by temporarily prepending any character.
+        // \uFEFF has the potential advantage of being zero-width/invisible.
+        node.innerHTML = '\uFEFF' + html;
+
+        // deleteData leaves an empty `TextNode` which offsets the index of all
+        // children. Definitely want to avoid this.
+        var textNode = node.firstChild;
+        if (textNode.data.length === 1) {
+          node.removeChild(textNode);
+        } else {
+          textNode.deleteData(0, 1);
+        }
+      } else {
+        node.innerHTML = html;
+      }
+    };
+  }
+}
+
+module.exports = setInnerHTML;
+
+},{"21":21}],149:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule setTextContent
+ */
+
+'use strict';
+
+var ExecutionEnvironment = _dereq_(21);
+var escapeTextContentForBrowser = _dereq_(116);
+var setInnerHTML = _dereq_(148);
+
+/**
+ * Set the textContent property of a node, ensuring that whitespace is preserved
+ * even in IE8. innerText is a poor substitute for textContent and, among many
+ * issues, inserts <br> instead of the literal newline chars. innerHTML behaves
+ * as it should.
+ *
+ * @param {DOMElement} node
+ * @param {string} text
+ * @internal
+ */
+var setTextContent = function(node, text) {
+  node.textContent = text;
+};
+
+if (ExecutionEnvironment.canUseDOM) {
+  if (!('textContent' in document.documentElement)) {
+    setTextContent = function(node, text) {
+      setInnerHTML(node, escapeTextContentForBrowser(text));
+    };
+  }
+}
+
+module.exports = setTextContent;
+
+},{"116":116,"148":148,"21":21}],150:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shallowEqual
+ */
+
+'use strict';
+
+/**
+ * Performs equality by iterating through keys on an object and returning
+ * false when any key has values which are not strictly equal between
+ * objA and objB. Returns true when the values of all keys are strictly equal.
+ *
+ * @return {boolean}
+ */
+function shallowEqual(objA, objB) {
+  if (objA === objB) {
+    return true;
+  }
+  var key;
+  // Test for A's keys different from B.
+  for (key in objA) {
+    if (objA.hasOwnProperty(key) &&
+        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
+      return false;
+    }
+  }
+  // Test for B's keys missing from A.
+  for (key in objB) {
+    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+module.exports = shallowEqual;
+
+},{}],151:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shouldUpdateReactComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var warning = _dereq_(154);
+
+/**
+ * Given a `prevElement` and `nextElement`, determines if the existing
+ * instance should be updated as opposed to being destroyed or replaced by a new
+ * instance. Both arguments are elements. This ensures that this logic can
+ * operate on stateless trees without any backing instance.
+ *
+ * @param {?object} prevElement
+ * @param {?object} nextElement
+ * @return {boolean} True if the existing instance should be updated.
+ * @protected
+ */
+function shouldUpdateReactComponent(prevElement, nextElement) {
+  if (prevElement != null && nextElement != null) {
+    var prevType = typeof prevElement;
+    var nextType = typeof nextElement;
+    if (prevType === 'string' || prevType === 'number') {
+      return (nextType === 'string' || nextType === 'number');
+    } else {
+      if (nextType === 'object' &&
+          prevElement.type === nextElement.type &&
+          prevElement.key === nextElement.key) {
+        var ownersMatch = prevElement._owner === nextElement._owner;
+        var prevName = null;
+        var nextName = null;
+        var nextDisplayName = null;
+        if ("production" !== "development") {
+          if (!ownersMatch) {
+            if (prevElement._owner != null &&
+                prevElement._owner.getPublicInstance() != null &&
+                prevElement._owner.getPublicInstance().constructor != null) {
+              prevName =
+                prevElement._owner.getPublicInstance().constructor.displayName;
+            }
+            if (nextElement._owner != null &&
+                nextElement._owner.getPublicInstance() != null &&
+                nextElement._owner.getPublicInstance().constructor != null) {
+              nextName =
+                nextElement._owner.getPublicInstance().constructor.displayName;
+            }
+            if (nextElement.type != null &&
+                nextElement.type.displayName != null) {
+              nextDisplayName = nextElement.type.displayName;
+            }
+            if (nextElement.type != null && typeof nextElement.type === 'string') {
+              nextDisplayName = nextElement.type;
+            }
+            if (typeof nextElement.type !== 'string' ||
+                nextElement.type === 'input' ||
+                nextElement.type === 'textarea') {
+              if ((prevElement._owner != null &&
+                  prevElement._owner._isOwnerNecessary === false) ||
+                  (nextElement._owner != null &&
+                  nextElement._owner._isOwnerNecessary === false)) {
+                if (prevElement._owner != null) {
+                  prevElement._owner._isOwnerNecessary = true;
+                }
+                if (nextElement._owner != null) {
+                  nextElement._owner._isOwnerNecessary = true;
+                }
+                ("production" !== "development" ? warning(
+                  false,
+                  '<%s /> is being rendered by both %s and %s using the same ' +
+                  'key (%s) in the same place. Currently, this means that ' +
+                  'they don\'t preserve state. This behavior should be very ' +
+                  'rare so we\'re considering deprecating it. Please contact ' +
+                  'the React team and explain your use case so that we can ' +
+                  'take that into consideration.',
+                  nextDisplayName || 'Unknown Component',
+                  prevName || '[Unknown]',
+                  nextName || '[Unknown]',
+                  prevElement.key
+                ) : null);
+              }
+            }
+          }
+        }
+        return ownersMatch;
+      }
+    }
+  }
+  return false;
+}
+
+module.exports = shouldUpdateReactComponent;
+
+},{"154":154}],152:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule toArray
+ * @typechecks
+ */
+
+var invariant = _dereq_(135);
+
+/**
+ * Convert array-like objects to arrays.
+ *
+ * This API assumes the caller knows the contents of the data type. For less
+ * well defined inputs use createArrayFromMixed.
+ *
+ * @param {object|function|filelist} obj
+ * @return {array}
+ */
+function toArray(obj) {
+  var length = obj.length;
+
+  // Some browse builtin objects can report typeof 'function' (e.g. NodeList in
+  // old versions of Safari).
+  ("production" !== "development" ? invariant(
+    !Array.isArray(obj) &&
+    (typeof obj === 'object' || typeof obj === 'function'),
+    'toArray: Array-like object expected'
+  ) : invariant(!Array.isArray(obj) &&
+  (typeof obj === 'object' || typeof obj === 'function')));
+
+  ("production" !== "development" ? invariant(
+    typeof length === 'number',
+    'toArray: Object needs a length property'
+  ) : invariant(typeof length === 'number'));
+
+  ("production" !== "development" ? invariant(
+    length === 0 ||
+    (length - 1) in obj,
+    'toArray: Object should have keys for indices'
+  ) : invariant(length === 0 ||
+  (length - 1) in obj));
+
+  // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
+  // without method will throw during the slice call and skip straight to the
+  // fallback.
+  if (obj.hasOwnProperty) {
+    try {
+      return Array.prototype.slice.call(obj);
+    } catch (e) {
+      // IE < 9 does not support Array#slice on collections objects
+    }
+  }
+
+  // Fall back to copying key by key. This assumes all keys have a value,
+  // so will not preserve sparsely populated inputs.
+  var ret = Array(length);
+  for (var ii = 0; ii < length; ii++) {
+    ret[ii] = obj[ii];
+  }
+  return ret;
+}
+
+module.exports = toArray;
+
+},{"135":135}],153:[function(_dereq_,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule traverseAllChildren
+ */
+
+'use strict';
+
+var ReactElement = _dereq_(57);
+var ReactFragment = _dereq_(63);
+var ReactInstanceHandles = _dereq_(66);
+
+var getIteratorFn = _dereq_(126);
+var invariant = _dereq_(135);
+var warning = _dereq_(154);
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+var SUBSEPARATOR = ':';
+
+/**
+ * TODO: Test that a single child and an array with one item have the same key
+ * pattern.
+ */
+
+var userProvidedKeyEscaperLookup = {
+  '=': '=0',
+  '.': '=1',
+  ':': '=2'
+};
+
+var userProvidedKeyEscapeRegex = /[=.:]/g;
+
+var didWarnAboutMaps = false;
+
+function userProvidedKeyEscaper(match) {
+  return userProvidedKeyEscaperLookup[match];
+}
+
+/**
+ * Generate a key string that identifies a component within a set.
+ *
+ * @param {*} component A component that could contain a manual key.
+ * @param {number} index Index that is used if a manual key is not provided.
+ * @return {string}
+ */
+function getComponentKey(component, index) {
+  if (component && component.key != null) {
+    // Explicit key
+    return wrapUserProvidedKey(component.key);
+  }
+  // Implicit key determined by the index in the set
+  return index.toString(36);
+}
+
+/**
+ * Escape a component key so that it is safe to use in a reactid.
+ *
+ * @param {*} key Component key to be escaped.
+ * @return {string} An escaped string.
+ */
+function escapeUserProvidedKey(text) {
+  return ('' + text).replace(
+    userProvidedKeyEscapeRegex,
+    userProvidedKeyEscaper
+  );
+}
+
+/**
+ * Wrap a `key` value explicitly provided by the user to distinguish it from
+ * implicitly-generated keys generated by a component's index in its parent.
+ *
+ * @param {string} key Value of a user-provided `key` attribute
+ * @return {string}
+ */
+function wrapUserProvidedKey(key) {
+  return '$' + escapeUserProvidedKey(key);
+}
+
+/**
+ * @param {?*} children Children tree container.
+ * @param {!string} nameSoFar Name of the key path so far.
+ * @param {!number} indexSoFar Number of children encountered until this point.
+ * @param {!function} callback Callback to invoke with each child found.
+ * @param {?*} traverseContext Used to pass information throughout the traversal
+ * process.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildrenImpl(
+  children,
+  nameSoFar,
+  indexSoFar,
+  callback,
+  traverseContext
+) {
+  var type = typeof children;
+
+  if (type === 'undefined' || type === 'boolean') {
+    // All of the above are perceived as null.
+    children = null;
+  }
+
+  if (children === null ||
+      type === 'string' ||
+      type === 'number' ||
+      ReactElement.isValidElement(children)) {
+    callback(
+      traverseContext,
+      children,
+      // If it's the only child, treat the name as if it was wrapped in an array
+      // so that it's consistent if the number of children grows.
+      nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
+      indexSoFar
+    );
+    return 1;
+  }
+
+  var child, nextName, nextIndex;
+  var subtreeCount = 0; // Count of children found in the current subtree.
+
+  if (Array.isArray(children)) {
+    for (var i = 0; i < children.length; i++) {
+      child = children[i];
+      nextName = (
+        (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+        getComponentKey(child, i)
+      );
+      nextIndex = indexSoFar + subtreeCount;
+      subtreeCount += traverseAllChildrenImpl(
+        child,
+        nextName,
+        nextIndex,
+        callback,
+        traverseContext
+      );
+    }
+  } else {
+    var iteratorFn = getIteratorFn(children);
+    if (iteratorFn) {
+      var iterator = iteratorFn.call(children);
+      var step;
+      if (iteratorFn !== children.entries) {
+        var ii = 0;
+        while (!(step = iterator.next()).done) {
+          child = step.value;
+          nextName = (
+            (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+            getComponentKey(child, ii++)
+          );
+          nextIndex = indexSoFar + subtreeCount;
+          subtreeCount += traverseAllChildrenImpl(
+            child,
+            nextName,
+            nextIndex,
+            callback,
+            traverseContext
+          );
+        }
+      } else {
+        if ("production" !== "development") {
+          ("production" !== "development" ? warning(
+            didWarnAboutMaps,
+            'Using Maps as children is not yet fully supported. It is an ' +
+            'experimental feature that might be removed. Convert it to a ' +
+            'sequence / iterable of keyed ReactElements instead.'
+          ) : null);
+          didWarnAboutMaps = true;
+        }
+        // Iterator will provide entry [k,v] tuples rather than values.
+        while (!(step = iterator.next()).done) {
+          var entry = step.value;
+          if (entry) {
+            child = entry[1];
+            nextName = (
+              (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+              wrapUserProvidedKey(entry[0]) + SUBSEPARATOR +
+              getComponentKey(child, 0)
+            );
+            nextIndex = indexSoFar + subtreeCount;
+            subtreeCount += traverseAllChildrenImpl(
+              child,
+              nextName,
+              nextIndex,
+              callback,
+              traverseContext
+            );
+          }
+        }
+      }
+    } else if (type === 'object') {
+      ("production" !== "development" ? invariant(
+        children.nodeType !== 1,
+        'traverseAllChildren(...): Encountered an invalid child; DOM ' +
+        'elements are not valid children of React components.'
+      ) : invariant(children.nodeType !== 1));
+      var fragment = ReactFragment.extract(children);
+      for (var key in fragment) {
+        if (fragment.hasOwnProperty(key)) {
+          child = fragment[key];
+          nextName = (
+            (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+            wrapUserProvidedKey(key) + SUBSEPARATOR +
+            getComponentKey(child, 0)
+          );
+          nextIndex = indexSoFar + subtreeCount;
+          subtreeCount += traverseAllChildrenImpl(
+            child,
+            nextName,
+            nextIndex,
+            callback,
+            traverseContext
+          );
+        }
+      }
+    }
+  }
+
+  return subtreeCount;
+}
+
+/**
+ * Traverses children that are typically specified as `props.children`, but
+ * might also be specified through attributes:
+ *
+ * - `traverseAllChildren(this.props.children, ...)`
+ * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
+ *
+ * The `traverseContext` is an optional argument that is passed through the
+ * entire traversal. It can be used to store accumulations or anything else that
+ * the callback might find relevant.
+ *
+ * @param {?*} children Children tree object.
+ * @param {!function} callback To invoke upon traversing each child.
+ * @param {?*} traverseContext Context for traversal.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildren(children, callback, traverseContext) {
+  if (children == null) {
+    return 0;
+  }
+
+  return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
+}
+
+module.exports = traverseAllChildren;
+
+},{"126":126,"135":135,"154":154,"57":57,"63":63,"66":66}],154:[function(_dereq_,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule warning
+ */
+
+"use strict";
+
+var emptyFunction = _dereq_(114);
+
+/**
+ * Similar to invariant but only logs a warning if the condition is not met.
+ * This can be used to log issues in development environments in critical
+ * paths. Removing the logging code for production environments will keep the
+ * same logic and follow the same code paths.
+ */
+
+var warning = emptyFunction;
+
+if ("production" !== "development") {
+  warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+    if (format === undefined) {
+      throw new Error(
+        '`warning(condition, format, ...args)` requires a warning ' +
+        'message argument'
+      );
+    }
+
+    if (format.length < 10 || /^[s\W]*$/.test(format)) {
+      throw new Error(
+        'The warning format should be able to uniquely identify this ' +
+        'warning. Please, use a more descriptive format than: ' + format
+      );
+    }
+
+    if (format.indexOf('Failed Composite propType: ') === 0) {
+      return; // Ignore CompositeComponent proptype check.
+    }
+
+    if (!condition) {
+      var argIndex = 0;
+      var message = 'Warning: ' + format.replace(/%s/g, function()  {return args[argIndex++];});
+      console.warn(message);
+      try {
+        // --- Welcome to debugging React ---
+        // This error was thrown as a convenience so that you can use this stack
+        // to find the callsite that caused this warning to fire.
+        throw new Error(message);
+      } catch(x) {}
+    }
+  };
+}
+
+module.exports = warning;
+
+},{"114":114}]},{},[1])(1)
+});
\ No newline at end of file
diff --git a/webcore/test/TC/react-dropzone.js b/webcore/test/TC/react-dropzone.js
new file mode 100644
index 0000000..a696f16
--- /dev/null
+++ b/webcore/test/TC/react-dropzone.js
@@ -0,0 +1,19804 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define("react-dropzone",[],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.reactDropzone = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u [...]
+var React = require('react');
+
+var Dropzone = React.createClass({displayName: "Dropzone",
+  getInitialState: function() {
+    return {
+      isDragActive: false
+    }
+  },
+
+  propTypes: {
+    onDrop: React.PropTypes.func.isRequired,
+    size: React.PropTypes.number,
+    style: React.PropTypes.object
+  },
+
+  onDragLeave: function(e) {
+    this.setState({
+      isDragActive: false
+    });
+  },
+
+  onDragOver: function(e) {
+    e.preventDefault();
+    e.dataTransfer.dropEffect = "copy";
+
+    this.setState({
+      isDragActive: true
+    });
+  },
+
+  onDrop: function(e) {
+    e.preventDefault();
+
+    this.setState({
+      isDragActive: false
+    });
+
+    var files;
+    if (e.dataTransfer) {
+      files = e.dataTransfer.files;
+    } else if (e.target) {
+      files = e.target.files;
+    }
+
+    if (this.props.onDrop) {
+      files = Array.prototype.slice.call(files);
+      this.props.onDrop(files);
+    }
+  },
+
+  onClick: function () {
+    this.refs.fileInput.getDOMNode().click();
+  },
+
+  render: function() {
+
+    var className = this.props.className || 'dropzone';
+    if (this.state.isDragActive) {
+      className += ' active';
+    };
+
+    var style = this.props.style || {
+      width: this.props.size || 100,
+      height: this.props.size || 100,
+      borderStyle: this.state.isDragActive ? "solid" : "dashed"
+    };
+
+    if (this.props.className) {
+      style = this.props.style;
+    }
+
+    return (
+      React.createElement("div", {className: className, style: style, onClick: this.onClick, onDragLeave: this.onDragLeave, onDragOver: this.onDragOver, onDrop: this.onDrop}, 
+        React.createElement("input", {style: {display: 'none'}, type: "file", multiple: true, ref: "fileInput", onChange: this.onDrop}), 
+        this.props.children
+      )
+    );
+  }
+
+});
+
+module.exports = Dropzone;
+
+
+},{"react":156}],2:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule AutoFocusMixin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var focusNode = require("./focusNode");
+
+var AutoFocusMixin = {
+  componentDidMount: function() {
+    if (this.props.autoFocus) {
+      focusNode(this.getDOMNode());
+    }
+  }
+};
+
+module.exports = AutoFocusMixin;
+
+},{"./focusNode":120}],3:[function(require,module,exports){
+/**
+ * Copyright 2013-2015 Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule BeforeInputEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var FallbackCompositionState = require("./FallbackCompositionState");
+var SyntheticCompositionEvent = require("./SyntheticCompositionEvent");
+var SyntheticInputEvent = require("./SyntheticInputEvent");
+
+var keyOf = require("./keyOf");
+
+var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
+var START_KEYCODE = 229;
+
+var canUseCompositionEvent = (
+  ExecutionEnvironment.canUseDOM &&
+  'CompositionEvent' in window
+);
+
+var documentMode = null;
+if (ExecutionEnvironment.canUseDOM && 'documentMode' in document) {
+  documentMode = document.documentMode;
+}
+
+// Webkit offers a very useful `textInput` event that can be used to
+// directly represent `beforeInput`. The IE `textinput` event is not as
+// useful, so we don't use it.
+var canUseTextInputEvent = (
+  ExecutionEnvironment.canUseDOM &&
+  'TextEvent' in window &&
+  !documentMode &&
+  !isPresto()
+);
+
+// In IE9+, we have access to composition events, but the data supplied
+// by the native compositionend event may be incorrect. Japanese ideographic
+// spaces, for instance (\u3000) are not recorded correctly.
+var useFallbackCompositionData = (
+  ExecutionEnvironment.canUseDOM &&
+  (
+    (!canUseCompositionEvent || documentMode && documentMode > 8 && documentMode <= 11)
+  )
+);
+
+/**
+ * Opera <= 12 includes TextEvent in window, but does not fire
+ * text input events. Rely on keypress instead.
+ */
+function isPresto() {
+  var opera = window.opera;
+  return (
+    typeof opera === 'object' &&
+    typeof opera.version === 'function' &&
+    parseInt(opera.version(), 10) <= 12
+  );
+}
+
+var SPACEBAR_CODE = 32;
+var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+// Events and their corresponding property names.
+var eventTypes = {
+  beforeInput: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onBeforeInput: null}),
+      captured: keyOf({onBeforeInputCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topCompositionEnd,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topTextInput,
+      topLevelTypes.topPaste
+    ]
+  },
+  compositionEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionEnd: null}),
+      captured: keyOf({onCompositionEndCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionEnd,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  },
+  compositionStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionStart: null}),
+      captured: keyOf({onCompositionStartCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionStart,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  },
+  compositionUpdate: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCompositionUpdate: null}),
+      captured: keyOf({onCompositionUpdateCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topCompositionUpdate,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyPress,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topMouseDown
+    ]
+  }
+};
+
+// Track whether we've ever handled a keypress on the space key.
+var hasSpaceKeypress = false;
+
+/**
+ * Return whether a native keypress event is assumed to be a command.
+ * This is required because Firefox fires `keypress` events for key commands
+ * (cut, copy, select-all, etc.) even though no character is inserted.
+ */
+function isKeypressCommand(nativeEvent) {
+  return (
+    (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
+    // ctrlKey && altKey is equivalent to AltGr, and is not a command.
+    !(nativeEvent.ctrlKey && nativeEvent.altKey)
+  );
+}
+
+
+/**
+ * Translate native top level events into event types.
+ *
+ * @param {string} topLevelType
+ * @return {object}
+ */
+function getCompositionEventType(topLevelType) {
+  switch (topLevelType) {
+    case topLevelTypes.topCompositionStart:
+      return eventTypes.compositionStart;
+    case topLevelTypes.topCompositionEnd:
+      return eventTypes.compositionEnd;
+    case topLevelTypes.topCompositionUpdate:
+      return eventTypes.compositionUpdate;
+  }
+}
+
+/**
+ * Does our fallback best-guess model think this event signifies that
+ * composition has begun?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackCompositionStart(topLevelType, nativeEvent) {
+  return (
+    topLevelType === topLevelTypes.topKeyDown &&
+    nativeEvent.keyCode === START_KEYCODE
+  );
+}
+
+/**
+ * Does our fallback mode think that this event is the end of composition?
+ *
+ * @param {string} topLevelType
+ * @param {object} nativeEvent
+ * @return {boolean}
+ */
+function isFallbackCompositionEnd(topLevelType, nativeEvent) {
+  switch (topLevelType) {
+    case topLevelTypes.topKeyUp:
+      // Command keys insert or clear IME input.
+      return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
+    case topLevelTypes.topKeyDown:
+      // Expect IME keyCode on each keydown. If we get any other
+      // code we must have exited earlier.
+      return (nativeEvent.keyCode !== START_KEYCODE);
+    case topLevelTypes.topKeyPress:
+    case topLevelTypes.topMouseDown:
+    case topLevelTypes.topBlur:
+      // Events are not possible without cancelling IME.
+      return true;
+    default:
+      return false;
+  }
+}
+
+/**
+ * Google Input Tools provides composition data via a CustomEvent,
+ * with the `data` property populated in the `detail` object. If this
+ * is available on the event object, use it. If not, this is a plain
+ * composition event and we have nothing special to extract.
+ *
+ * @param {object} nativeEvent
+ * @return {?string}
+ */
+function getDataFromCustomEvent(nativeEvent) {
+  var detail = nativeEvent.detail;
+  if (typeof detail === 'object' && 'data' in detail) {
+    return detail.data;
+  }
+  return null;
+}
+
+// Track the current IME composition fallback object, if any.
+var currentComposition = null;
+
+/**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?object} A SyntheticCompositionEvent.
+ */
+function extractCompositionEvent(
+  topLevelType,
+  topLevelTarget,
+  topLevelTargetID,
+  nativeEvent
+) {
+  var eventType;
+  var fallbackData;
+
+  if (canUseCompositionEvent) {
+    eventType = getCompositionEventType(topLevelType);
+  } else if (!currentComposition) {
+    if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
+      eventType = eventTypes.compositionStart;
+    }
+  } else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
+    eventType = eventTypes.compositionEnd;
+  }
+
+  if (!eventType) {
+    return null;
+  }
+
+  if (useFallbackCompositionData) {
+    // The current composition is stored statically and must not be
+    // overwritten while composition continues.
+    if (!currentComposition && eventType === eventTypes.compositionStart) {
+      currentComposition = FallbackCompositionState.getPooled(topLevelTarget);
+    } else if (eventType === eventTypes.compositionEnd) {
+      if (currentComposition) {
+        fallbackData = currentComposition.getData();
+      }
+    }
+  }
+
+  var event = SyntheticCompositionEvent.getPooled(
+    eventType,
+    topLevelTargetID,
+    nativeEvent
+  );
+
+  if (fallbackData) {
+    // Inject data generated from fallback path into the synthetic event.
+    // This matches the property of native CompositionEventInterface.
+    event.data = fallbackData;
+  } else {
+    var customData = getDataFromCustomEvent(nativeEvent);
+    if (customData !== null) {
+      event.data = customData;
+    }
+  }
+
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+  return event;
+}
+
+/**
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?string} The string corresponding to this `beforeInput` event.
+ */
+function getNativeBeforeInputChars(topLevelType, nativeEvent) {
+  switch (topLevelType) {
+    case topLevelTypes.topCompositionEnd:
+      return getDataFromCustomEvent(nativeEvent);
+    case topLevelTypes.topKeyPress:
+      /**
+       * If native `textInput` events are available, our goal is to make
+       * use of them. However, there is a special case: the spacebar key.
+       * In Webkit, preventing default on a spacebar `textInput` event
+       * cancels character insertion, but it *also* causes the browser
+       * to fall back to its default spacebar behavior of scrolling the
+       * page.
+       *
+       * Tracking at:
+       * https://code.google.com/p/chromium/issues/detail?id=355103
+       *
+       * To avoid this issue, use the keypress event as if no `textInput`
+       * event is available.
+       */
+      var which = nativeEvent.which;
+      if (which !== SPACEBAR_CODE) {
+        return null;
+      }
+
+      hasSpaceKeypress = true;
+      return SPACEBAR_CHAR;
+
+    case topLevelTypes.topTextInput:
+      // Record the characters to be added to the DOM.
+      var chars = nativeEvent.data;
+
+      // If it's a spacebar character, assume that we have already handled
+      // it at the keypress level and bail immediately. Android Chrome
+      // doesn't give us keycodes, so we need to blacklist it.
+      if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
+        return null;
+      }
+
+      return chars;
+
+    default:
+      // For other native event types, do nothing.
+      return null;
+  }
+}
+
+/**
+ * For browsers that do not provide the `textInput` event, extract the
+ * appropriate string to use for SyntheticInputEvent.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?string} The fallback string for this `beforeInput` event.
+ */
+function getFallbackBeforeInputChars(topLevelType, nativeEvent) {
+  // If we are currently composing (IME) and using a fallback to do so,
+  // try to extract the composed characters from the fallback object.
+  if (currentComposition) {
+    if (
+      topLevelType === topLevelTypes.topCompositionEnd ||
+      isFallbackCompositionEnd(topLevelType, nativeEvent)
+    ) {
+      var chars = currentComposition.getData();
+      FallbackCompositionState.release(currentComposition);
+      currentComposition = null;
+      return chars;
+    }
+    return null;
+  }
+
+  switch (topLevelType) {
+    case topLevelTypes.topPaste:
+      // If a paste event occurs after a keypress, throw out the input
+      // chars. Paste events should not lead to BeforeInput events.
+      return null;
+    case topLevelTypes.topKeyPress:
+      /**
+       * As of v27, Firefox may fire keypress events even when no character
+       * will be inserted. A few possibilities:
+       *
+       * - `which` is `0`. Arrow keys, Esc key, etc.
+       *
+       * - `which` is the pressed key code, but no char is available.
+       *   Ex: 'AltGr + d` in Polish. There is no modified character for
+       *   this key combination and no character is inserted into the
+       *   document, but FF fires the keypress for char code `100` anyway.
+       *   No `input` event will occur.
+       *
+       * - `which` is the pressed key code, but a command combination is
+       *   being used. Ex: `Cmd+C`. No character is inserted, and no
+       *   `input` event will occur.
+       */
+      if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
+        return String.fromCharCode(nativeEvent.which);
+      }
+      return null;
+    case topLevelTypes.topCompositionEnd:
+      return useFallbackCompositionData ? null : nativeEvent.data;
+    default:
+      return null;
+  }
+}
+
+/**
+ * Extract a SyntheticInputEvent for `beforeInput`, based on either native
+ * `textInput` or fallback behavior.
+ *
+ * @param {string} topLevelType Record from `EventConstants`.
+ * @param {DOMEventTarget} topLevelTarget The listening component root node.
+ * @param {string} topLevelTargetID ID of `topLevelTarget`.
+ * @param {object} nativeEvent Native browser event.
+ * @return {?object} A SyntheticInputEvent.
+ */
+function extractBeforeInputEvent(
+  topLevelType,
+  topLevelTarget,
+  topLevelTargetID,
+  nativeEvent
+) {
+  var chars;
+
+  if (canUseTextInputEvent) {
+    chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
+  } else {
+    chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
+  }
+
+  // If no characters are being inserted, no BeforeInput event should
+  // be fired.
+  if (!chars) {
+    return null;
+  }
+
+  var event = SyntheticInputEvent.getPooled(
+    eventTypes.beforeInput,
+    topLevelTargetID,
+    nativeEvent
+  );
+
+  event.data = chars;
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+  return event;
+}
+
+/**
+ * Create an `onBeforeInput` event to match
+ * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
+ *
+ * This event plugin is based on the native `textInput` event
+ * available in Chrome, Safari, Opera, and IE. This event fires after
+ * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
+ *
+ * `beforeInput` is spec'd but not implemented in any browsers, and
+ * the `input` event does not provide any useful information about what has
+ * actually been added, contrary to the spec. Thus, `textInput` is the best
+ * available event to identify the characters that have actually been inserted
+ * into the target node.
+ *
+ * This plugin is also responsible for emitting `composition` events, thus
+ * allowing us to share composition fallback code for both `beforeInput` and
+ * `composition` event types.
+ */
+var BeforeInputEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID,
+    nativeEvent
+  ) {
+    return [
+      extractCompositionEvent(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent
+      ),
+      extractBeforeInputEvent(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID,
+        nativeEvent
+      )
+    ];
+  }
+};
+
+module.exports = BeforeInputEventPlugin;
+
+},{"./EventConstants":15,"./EventPropagators":20,"./ExecutionEnvironment":21,"./FallbackCompositionState":22,"./SyntheticCompositionEvent":94,"./SyntheticInputEvent":98,"./keyOf":142}],4:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSProperty
+ */
+
+'use strict';
+
+/**
+ * CSS properties which accept numbers but are not in units of "px".
+ */
+var isUnitlessNumber = {
+  boxFlex: true,
+  boxFlexGroup: true,
+  columnCount: true,
+  flex: true,
+  flexGrow: true,
+  flexShrink: true,
+  fontWeight: true,
+  lineClamp: true,
+  lineHeight: true,
+  opacity: true,
+  order: true,
+  orphans: true,
+  widows: true,
+  zIndex: true,
+  zoom: true,
+
+  // SVG-related properties
+  fillOpacity: true,
+  strokeOpacity: true
+};
+
+/**
+ * @param {string} prefix vendor-specific prefix, eg: Webkit
+ * @param {string} key style name, eg: transitionDuration
+ * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
+ * WebkitTransitionDuration
+ */
+function prefixKey(prefix, key) {
+  return prefix + key.charAt(0).toUpperCase() + key.substring(1);
+}
+
+/**
+ * Support style names that may come passed in prefixed by adding permutations
+ * of vendor prefixes.
+ */
+var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
+
+// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
+// infinite loop, because it iterates over the newly added props too.
+Object.keys(isUnitlessNumber).forEach(function(prop) {
+  prefixes.forEach(function(prefix) {
+    isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
+  });
+});
+
+/**
+ * Most style properties can be unset by doing .style[prop] = '' but IE8
+ * doesn't like doing that with shorthand properties so for the properties that
+ * IE8 breaks on, which are listed here, we instead unset each of the
+ * individual properties. See http://bugs.jquery.com/ticket/12385.
+ * The 4-value 'clock' properties like margin, padding, border-width seem to
+ * behave without any problems. Curiously, list-style works too without any
+ * special prodding.
+ */
+var shorthandPropertyExpansions = {
+  background: {
+    backgroundImage: true,
+    backgroundPosition: true,
+    backgroundRepeat: true,
+    backgroundColor: true
+  },
+  border: {
+    borderWidth: true,
+    borderStyle: true,
+    borderColor: true
+  },
+  borderBottom: {
+    borderBottomWidth: true,
+    borderBottomStyle: true,
+    borderBottomColor: true
+  },
+  borderLeft: {
+    borderLeftWidth: true,
+    borderLeftStyle: true,
+    borderLeftColor: true
+  },
+  borderRight: {
+    borderRightWidth: true,
+    borderRightStyle: true,
+    borderRightColor: true
+  },
+  borderTop: {
+    borderTopWidth: true,
+    borderTopStyle: true,
+    borderTopColor: true
+  },
+  font: {
+    fontStyle: true,
+    fontVariant: true,
+    fontWeight: true,
+    fontSize: true,
+    lineHeight: true,
+    fontFamily: true
+  }
+};
+
+var CSSProperty = {
+  isUnitlessNumber: isUnitlessNumber,
+  shorthandPropertyExpansions: shorthandPropertyExpansions
+};
+
+module.exports = CSSProperty;
+
+},{}],5:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSPropertyOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CSSProperty = require("./CSSProperty");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var camelizeStyleName = require("./camelizeStyleName");
+var dangerousStyleValue = require("./dangerousStyleValue");
+var hyphenateStyleName = require("./hyphenateStyleName");
+var memoizeStringOnly = require("./memoizeStringOnly");
+var warning = require("./warning");
+
+var processStyleName = memoizeStringOnly(function(styleName) {
+  return hyphenateStyleName(styleName);
+});
+
+var styleFloatAccessor = 'cssFloat';
+if (ExecutionEnvironment.canUseDOM) {
+  // IE8 only supports accessing cssFloat (standard) as styleFloat
+  if (document.documentElement.style.cssFloat === undefined) {
+    styleFloatAccessor = 'styleFloat';
+  }
+}
+
+if ("production" !== process.env.NODE_ENV) {
+  // 'msTransform' is correct, but the other prefixes should be capitalized
+  var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/;
+
+  // style values shouldn't contain a semicolon
+  var badStyleValueWithSemicolonPattern = /;\s*$/;
+
+  var warnedStyleNames = {};
+  var warnedStyleValues = {};
+
+  var warnHyphenatedStyleName = function(name) {
+    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
+      return;
+    }
+
+    warnedStyleNames[name] = true;
+    ("production" !== process.env.NODE_ENV ? warning(
+      false,
+      'Unsupported style property %s. Did you mean %s?',
+      name,
+      camelizeStyleName(name)
+    ) : null);
+  };
+
+  var warnBadVendoredStyleName = function(name) {
+    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
+      return;
+    }
+
+    warnedStyleNames[name] = true;
+    ("production" !== process.env.NODE_ENV ? warning(
+      false,
+      'Unsupported vendor-prefixed style property %s. Did you mean %s?',
+      name,
+      name.charAt(0).toUpperCase() + name.slice(1)
+    ) : null);
+  };
+
+  var warnStyleValueWithSemicolon = function(name, value) {
+    if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) {
+      return;
+    }
+
+    warnedStyleValues[value] = true;
+    ("production" !== process.env.NODE_ENV ? warning(
+      false,
+      'Style property values shouldn\'t contain a semicolon. ' +
+      'Try "%s: %s" instead.',
+      name,
+      value.replace(badStyleValueWithSemicolonPattern, '')
+    ) : null);
+  };
+
+  /**
+   * @param {string} name
+   * @param {*} value
+   */
+  var warnValidStyle = function(name, value) {
+    if (name.indexOf('-') > -1) {
+      warnHyphenatedStyleName(name);
+    } else if (badVendoredStyleNamePattern.test(name)) {
+      warnBadVendoredStyleName(name);
+    } else if (badStyleValueWithSemicolonPattern.test(value)) {
+      warnStyleValueWithSemicolon(name, value);
+    }
+  };
+}
+
+/**
+ * Operations for dealing with CSS properties.
+ */
+var CSSPropertyOperations = {
+
+  /**
+   * Serializes a mapping of style properties for use as inline styles:
+   *
+   *   > createMarkupForStyles({width: '200px', height: 0})
+   *   "width:200px;height:0;"
+   *
+   * Undefined values are ignored so that declarative programming is easier.
+   * The result should be HTML-escaped before insertion into the DOM.
+   *
+   * @param {object} styles
+   * @return {?string}
+   */
+  createMarkupForStyles: function(styles) {
+    var serialized = '';
+    for (var styleName in styles) {
+      if (!styles.hasOwnProperty(styleName)) {
+        continue;
+      }
+      var styleValue = styles[styleName];
+      if ("production" !== process.env.NODE_ENV) {
+        warnValidStyle(styleName, styleValue);
+      }
+      if (styleValue != null) {
+        serialized += processStyleName(styleName) + ':';
+        serialized += dangerousStyleValue(styleName, styleValue) + ';';
+      }
+    }
+    return serialized || null;
+  },
+
+  /**
+   * Sets the value for multiple styles on a node.  If a value is specified as
+   * '' (empty string), the corresponding style property will be unset.
+   *
+   * @param {DOMElement} node
+   * @param {object} styles
+   */
+  setValueForStyles: function(node, styles) {
+    var style = node.style;
+    for (var styleName in styles) {
+      if (!styles.hasOwnProperty(styleName)) {
+        continue;
+      }
+      if ("production" !== process.env.NODE_ENV) {
+        warnValidStyle(styleName, styles[styleName]);
+      }
+      var styleValue = dangerousStyleValue(styleName, styles[styleName]);
+      if (styleName === 'float') {
+        styleName = styleFloatAccessor;
+      }
+      if (styleValue) {
+        style[styleName] = styleValue;
+      } else {
+        var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
+        if (expansion) {
+          // Shorthand property that IE8 won't like unsetting, so unset each
+          // component to placate it
+          for (var individualStyleName in expansion) {
+            style[individualStyleName] = '';
+          }
+        } else {
+          style[styleName] = '';
+        }
+      }
+    }
+  }
+
+};
+
+module.exports = CSSPropertyOperations;
+
+}).call(this,require('_process'))
+},{"./CSSProperty":4,"./ExecutionEnvironment":21,"./camelizeStyleName":109,"./dangerousStyleValue":114,"./hyphenateStyleName":134,"./memoizeStringOnly":144,"./warning":155,"_process":157}],6:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CallbackQueue
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+/**
+ * A specialized pseudo-event module to help keep track of components waiting to
+ * be notified when their DOM representations are available for use.
+ *
+ * This implements `PooledClass`, so you should never need to instantiate this.
+ * Instead, use `CallbackQueue.getPooled()`.
+ *
+ * @class ReactMountReady
+ * @implements PooledClass
+ * @internal
+ */
+function CallbackQueue() {
+  this._callbacks = null;
+  this._contexts = null;
+}
+
+assign(CallbackQueue.prototype, {
+
+  /**
+   * Enqueues a callback to be invoked when `notifyAll` is invoked.
+   *
+   * @param {function} callback Invoked when `notifyAll` is invoked.
+   * @param {?object} context Context to call `callback` with.
+   * @internal
+   */
+  enqueue: function(callback, context) {
+    this._callbacks = this._callbacks || [];
+    this._contexts = this._contexts || [];
+    this._callbacks.push(callback);
+    this._contexts.push(context);
+  },
+
+  /**
+   * Invokes all enqueued callbacks and clears the queue. This is invoked after
+   * the DOM representation of a component has been created or updated.
+   *
+   * @internal
+   */
+  notifyAll: function() {
+    var callbacks = this._callbacks;
+    var contexts = this._contexts;
+    if (callbacks) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        callbacks.length === contexts.length,
+        'Mismatched list of contexts in callback queue'
+      ) : invariant(callbacks.length === contexts.length));
+      this._callbacks = null;
+      this._contexts = null;
+      for (var i = 0, l = callbacks.length; i < l; i++) {
+        callbacks[i].call(contexts[i]);
+      }
+      callbacks.length = 0;
+      contexts.length = 0;
+    }
+  },
+
+  /**
+   * Resets the internal queue.
+   *
+   * @internal
+   */
+  reset: function() {
+    this._callbacks = null;
+    this._contexts = null;
+  },
+
+  /**
+   * `PooledClass` looks for this.
+   */
+  destructor: function() {
+    this.reset();
+  }
+
+});
+
+PooledClass.addPoolingTo(CallbackQueue);
+
+module.exports = CallbackQueue;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./PooledClass":28,"./invariant":136,"_process":157}],7:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ChangeEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPropagators = require("./EventPropagators");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var ReactUpdates = require("./ReactUpdates");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var isEventSupported = require("./isEventSupported");
+var isTextInputElement = require("./isTextInputElement");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  change: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onChange: null}),
+      captured: keyOf({onChangeCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topChange,
+      topLevelTypes.topClick,
+      topLevelTypes.topFocus,
+      topLevelTypes.topInput,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topKeyUp,
+      topLevelTypes.topSelectionChange
+    ]
+  }
+};
+
+/**
+ * For IE shims
+ */
+var activeElement = null;
+var activeElementID = null;
+var activeElementValue = null;
+var activeElementValueProp = null;
+
+/**
+ * SECTION: handle `change` event
+ */
+function shouldUseChangeEvent(elem) {
+  return (
+    elem.nodeName === 'SELECT' ||
+    (elem.nodeName === 'INPUT' && elem.type === 'file')
+  );
+}
+
+var doesChangeEventBubble = false;
+if (ExecutionEnvironment.canUseDOM) {
+  // See `handleChange` comment below
+  doesChangeEventBubble = isEventSupported('change') && (
+    (!('documentMode' in document) || document.documentMode > 8)
+  );
+}
+
+function manualDispatchChangeEvent(nativeEvent) {
+  var event = SyntheticEvent.getPooled(
+    eventTypes.change,
+    activeElementID,
+    nativeEvent
+  );
+  EventPropagators.accumulateTwoPhaseDispatches(event);
+
+  // If change and propertychange bubbled, we'd just bind to it like all the
+  // other events and have it go through ReactBrowserEventEmitter. Since it
+  // doesn't, we manually listen for the events and so we have to enqueue and
+  // process the abstract event manually.
+  //
+  // Batching is necessary here in order to ensure that all event handlers run
+  // before the next rerender (including event handlers attached to ancestor
+  // elements instead of directly on the input). Without this, controlled
+  // components don't work properly in conjunction with event bubbling because
+  // the component is rerendered and the value reverted before all the event
+  // handlers can run. See https://github.com/facebook/react/issues/708.
+  ReactUpdates.batchedUpdates(runEventInBatch, event);
+}
+
+function runEventInBatch(event) {
+  EventPluginHub.enqueueEvents(event);
+  EventPluginHub.processEventQueue();
+}
+
+function startWatchingForChangeEventIE8(target, targetID) {
+  activeElement = target;
+  activeElementID = targetID;
+  activeElement.attachEvent('onchange', manualDispatchChangeEvent);
+}
+
+function stopWatchingForChangeEventIE8() {
+  if (!activeElement) {
+    return;
+  }
+  activeElement.detachEvent('onchange', manualDispatchChangeEvent);
+  activeElement = null;
+  activeElementID = null;
+}
+
+function getTargetIDForChangeEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topChange) {
+    return topLevelTargetID;
+  }
+}
+function handleEventsForChangeEventIE8(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topFocus) {
+    // stopWatching() should be a noop here but we call it just in case we
+    // missed a blur event somehow.
+    stopWatchingForChangeEventIE8();
+    startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
+  } else if (topLevelType === topLevelTypes.topBlur) {
+    stopWatchingForChangeEventIE8();
+  }
+}
+
+
+/**
+ * SECTION: handle `input` event
+ */
+var isInputEventSupported = false;
+if (ExecutionEnvironment.canUseDOM) {
+  // IE9 claims to support the input event but fails to trigger it when
+  // deleting text, so we ignore its input events
+  isInputEventSupported = isEventSupported('input') && (
+    (!('documentMode' in document) || document.documentMode > 9)
+  );
+}
+
+/**
+ * (For old IE.) Replacement getter/setter for the `value` property that gets
+ * set on the active element.
+ */
+var newValueProp =  {
+  get: function() {
+    return activeElementValueProp.get.call(this);
+  },
+  set: function(val) {
+    // Cast to a string so we can do equality checks.
+    activeElementValue = '' + val;
+    activeElementValueProp.set.call(this, val);
+  }
+};
+
+/**
+ * (For old IE.) Starts tracking propertychange events on the passed-in element
+ * and override the value property so that we can distinguish user events from
+ * value changes in JS.
+ */
+function startWatchingForValueChange(target, targetID) {
+  activeElement = target;
+  activeElementID = targetID;
+  activeElementValue = target.value;
+  activeElementValueProp = Object.getOwnPropertyDescriptor(
+    target.constructor.prototype,
+    'value'
+  );
+
+  Object.defineProperty(activeElement, 'value', newValueProp);
+  activeElement.attachEvent('onpropertychange', handlePropertyChange);
+}
+
+/**
+ * (For old IE.) Removes the event listeners from the currently-tracked element,
+ * if any exists.
+ */
+function stopWatchingForValueChange() {
+  if (!activeElement) {
+    return;
+  }
+
+  // delete restores the original property definition
+  delete activeElement.value;
+  activeElement.detachEvent('onpropertychange', handlePropertyChange);
+
+  activeElement = null;
+  activeElementID = null;
+  activeElementValue = null;
+  activeElementValueProp = null;
+}
+
+/**
+ * (For old IE.) Handles a propertychange event, sending a `change` event if
+ * the value of the active element has changed.
+ */
+function handlePropertyChange(nativeEvent) {
+  if (nativeEvent.propertyName !== 'value') {
+    return;
+  }
+  var value = nativeEvent.srcElement.value;
+  if (value === activeElementValue) {
+    return;
+  }
+  activeElementValue = value;
+
+  manualDispatchChangeEvent(nativeEvent);
+}
+
+/**
+ * If a `change` event should be fired, returns the target's ID.
+ */
+function getTargetIDForInputEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topInput) {
+    // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
+    // what we want so fall through here and trigger an abstract event
+    return topLevelTargetID;
+  }
+}
+
+// For IE8 and IE9.
+function handleEventsForInputEventIE(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topFocus) {
+    // In IE8, we can capture almost all .value changes by adding a
+    // propertychange handler and looking for events with propertyName
+    // equal to 'value'
+    // In IE9, propertychange fires for most input events but is buggy and
+    // doesn't fire when text is deleted, but conveniently, selectionchange
+    // appears to fire in all of the remaining cases so we catch those and
+    // forward the event if the value has changed
+    // In either case, we don't want to call the event handler if the value
+    // is changed from JS so we redefine a setter for `.value` that updates
+    // our activeElementValue variable, allowing us to ignore those changes
+    //
+    // stopWatching() should be a noop here but we call it just in case we
+    // missed a blur event somehow.
+    stopWatchingForValueChange();
+    startWatchingForValueChange(topLevelTarget, topLevelTargetID);
+  } else if (topLevelType === topLevelTypes.topBlur) {
+    stopWatchingForValueChange();
+  }
+}
+
+// For IE8 and IE9.
+function getTargetIDForInputEventIE(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topSelectionChange ||
+      topLevelType === topLevelTypes.topKeyUp ||
+      topLevelType === topLevelTypes.topKeyDown) {
+    // On the selectionchange event, the target is just document which isn't
+    // helpful for us so just check activeElement instead.
+    //
+    // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
+    // propertychange on the first input event after setting `value` from a
+    // script and fires only keydown, keypress, keyup. Catching keyup usually
+    // gets it and catching keydown lets us fire an event for the first
+    // keystroke if user does a key repeat (it'll be a little delayed: right
+    // before the second keystroke). Other input methods (e.g., paste) seem to
+    // fire selectionchange normally.
+    if (activeElement && activeElement.value !== activeElementValue) {
+      activeElementValue = activeElement.value;
+      return activeElementID;
+    }
+  }
+}
+
+
+/**
+ * SECTION: handle `click` event
+ */
+function shouldUseClickEvent(elem) {
+  // Use the `click` event to detect changes to checkbox and radio inputs.
+  // This approach works across all browsers, whereas `change` does not fire
+  // until `blur` in IE8.
+  return (
+    elem.nodeName === 'INPUT' &&
+    (elem.type === 'checkbox' || elem.type === 'radio')
+  );
+}
+
+function getTargetIDForClickEvent(
+    topLevelType,
+    topLevelTarget,
+    topLevelTargetID) {
+  if (topLevelType === topLevelTypes.topClick) {
+    return topLevelTargetID;
+  }
+}
+
+/**
+ * This plugin creates an `onChange` event that normalizes change events
+ * across form elements. This event fires at a time when it's possible to
+ * change the element's value without seeing a flicker.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - select
+ */
+var ChangeEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+
+    var getTargetIDFunc, handleEventFunc;
+    if (shouldUseChangeEvent(topLevelTarget)) {
+      if (doesChangeEventBubble) {
+        getTargetIDFunc = getTargetIDForChangeEvent;
+      } else {
+        handleEventFunc = handleEventsForChangeEventIE8;
+      }
+    } else if (isTextInputElement(topLevelTarget)) {
+      if (isInputEventSupported) {
+        getTargetIDFunc = getTargetIDForInputEvent;
+      } else {
+        getTargetIDFunc = getTargetIDForInputEventIE;
+        handleEventFunc = handleEventsForInputEventIE;
+      }
+    } else if (shouldUseClickEvent(topLevelTarget)) {
+      getTargetIDFunc = getTargetIDForClickEvent;
+    }
+
+    if (getTargetIDFunc) {
+      var targetID = getTargetIDFunc(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID
+      );
+      if (targetID) {
+        var event = SyntheticEvent.getPooled(
+          eventTypes.change,
+          targetID,
+          nativeEvent
+        );
+        EventPropagators.accumulateTwoPhaseDispatches(event);
+        return event;
+      }
+    }
+
+    if (handleEventFunc) {
+      handleEventFunc(
+        topLevelType,
+        topLevelTarget,
+        topLevelTargetID
+      );
+    }
+  }
+
+};
+
+module.exports = ChangeEventPlugin;
+
+},{"./EventConstants":15,"./EventPluginHub":17,"./EventPropagators":20,"./ExecutionEnvironment":21,"./ReactUpdates":88,"./SyntheticEvent":96,"./isEventSupported":137,"./isTextInputElement":139,"./keyOf":142}],8:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ClientReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+var nextReactRootIndex = 0;
+
+var ClientReactRootIndex = {
+  createReactRootIndex: function() {
+    return nextReactRootIndex++;
+  }
+};
+
+module.exports = ClientReactRootIndex;
+
+},{}],9:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMChildrenOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var Danger = require("./Danger");
+var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");
+
+var setTextContent = require("./setTextContent");
+var invariant = require("./invariant");
+
+/**
+ * Inserts `childNode` as a child of `parentNode` at the `index`.
+ *
+ * @param {DOMElement} parentNode Parent node in which to insert.
+ * @param {DOMElement} childNode Child node to insert.
+ * @param {number} index Index at which to insert the child.
+ * @internal
+ */
+function insertChildAt(parentNode, childNode, index) {
+  // By exploiting arrays returning `undefined` for an undefined index, we can
+  // rely exclusively on `insertBefore(node, null)` instead of also using
+  // `appendChild(node)`. However, using `undefined` is not allowed by all
+  // browsers so we must replace it with `null`.
+  parentNode.insertBefore(
+    childNode,
+    parentNode.childNodes[index] || null
+  );
+}
+
+/**
+ * Operations for updating with DOM children.
+ */
+var DOMChildrenOperations = {
+
+  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,
+
+  updateTextContent: setTextContent,
+
+  /**
+   * Updates a component's children by processing a series of updates. The
+   * update configurations are each expected to have a `parentNode` property.
+   *
+   * @param {array<object>} updates List of update configurations.
+   * @param {array<string>} markupList List of markup strings.
+   * @internal
+   */
+  processUpdates: function(updates, markupList) {
+    var update;
+    // Mapping from parent IDs to initial child orderings.
+    var initialChildren = null;
+    // List of children that will be moved or removed.
+    var updatedChildren = null;
+
+    for (var i = 0; i < updates.length; i++) {
+      update = updates[i];
+      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
+          update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
+        var updatedIndex = update.fromIndex;
+        var updatedChild = update.parentNode.childNodes[updatedIndex];
+        var parentID = update.parentID;
+
+        ("production" !== process.env.NODE_ENV ? invariant(
+          updatedChild,
+          'processUpdates(): Unable to find child %s of element. This ' +
+          'probably means the DOM was unexpectedly mutated (e.g., by the ' +
+          'browser), usually due to forgetting a <tbody> when using tables, ' +
+          'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' +
+          'in an <svg> parent. Try inspecting the child nodes of the element ' +
+          'with React ID `%s`.',
+          updatedIndex,
+          parentID
+        ) : invariant(updatedChild));
+
+        initialChildren = initialChildren || {};
+        initialChildren[parentID] = initialChildren[parentID] || [];
+        initialChildren[parentID][updatedIndex] = updatedChild;
+
+        updatedChildren = updatedChildren || [];
+        updatedChildren.push(updatedChild);
+      }
+    }
+
+    var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);
+
+    // Remove updated children first so that `toIndex` is consistent.
+    if (updatedChildren) {
+      for (var j = 0; j < updatedChildren.length; j++) {
+        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
+      }
+    }
+
+    for (var k = 0; k < updates.length; k++) {
+      update = updates[k];
+      switch (update.type) {
+        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
+          insertChildAt(
+            update.parentNode,
+            renderedMarkup[update.markupIndex],
+            update.toIndex
+          );
+          break;
+        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
+          insertChildAt(
+            update.parentNode,
+            initialChildren[update.parentID][update.fromIndex],
+            update.toIndex
+          );
+          break;
+        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
+          setTextContent(
+            update.parentNode,
+            update.textContent
+          );
+          break;
+        case ReactMultiChildUpdateTypes.REMOVE_NODE:
+          // Already removed by the for-loop above.
+          break;
+      }
+    }
+  }
+
+};
+
+module.exports = DOMChildrenOperations;
+
+}).call(this,require('_process'))
+},{"./Danger":12,"./ReactMultiChildUpdateTypes":73,"./invariant":136,"./setTextContent":150,"_process":157}],10:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMProperty
+ * @typechecks static-only
+ */
+
+/*jslint bitwise: true */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+function checkMask(value, bitmask) {
+  return (value & bitmask) === bitmask;
+}
+
+var DOMPropertyInjection = {
+  /**
+   * Mapping from normalized, camelcased property names to a configuration that
+   * specifies how the associated DOM property should be accessed or rendered.
+   */
+  MUST_USE_ATTRIBUTE: 0x1,
+  MUST_USE_PROPERTY: 0x2,
+  HAS_SIDE_EFFECTS: 0x4,
+  HAS_BOOLEAN_VALUE: 0x8,
+  HAS_NUMERIC_VALUE: 0x10,
+  HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
+  HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,
+
+  /**
+   * Inject some specialized knowledge about the DOM. This takes a config object
+   * with the following properties:
+   *
+   * isCustomAttribute: function that given an attribute name will return true
+   * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
+   * attributes where it's impossible to enumerate all of the possible
+   * attribute names,
+   *
+   * Properties: object mapping DOM property name to one of the
+   * DOMPropertyInjection constants or null. If your attribute isn't in here,
+   * it won't get written to the DOM.
+   *
+   * DOMAttributeNames: object mapping React attribute name to the DOM
+   * attribute name. Attribute names not specified use the **lowercase**
+   * normalized name.
+   *
+   * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
+   * Property names not specified use the normalized name.
+   *
+   * DOMMutationMethods: Properties that require special mutation methods. If
+   * `value` is undefined, the mutation method should unset the property.
+   *
+   * @param {object} domPropertyConfig the config as described above.
+   */
+  injectDOMPropertyConfig: function(domPropertyConfig) {
+    var Properties = domPropertyConfig.Properties || {};
+    var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
+    var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
+    var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
+
+    if (domPropertyConfig.isCustomAttribute) {
+      DOMProperty._isCustomAttributeFunctions.push(
+        domPropertyConfig.isCustomAttribute
+      );
+    }
+
+    for (var propName in Properties) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        !DOMProperty.isStandardName.hasOwnProperty(propName),
+        'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
+        '\'%s\' which has already been injected. You may be accidentally ' +
+        'injecting the same DOM property config twice, or you may be ' +
+        'injecting two configs that have conflicting property names.',
+        propName
+      ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));
+
+      DOMProperty.isStandardName[propName] = true;
+
+      var lowerCased = propName.toLowerCase();
+      DOMProperty.getPossibleStandardName[lowerCased] = propName;
+
+      if (DOMAttributeNames.hasOwnProperty(propName)) {
+        var attributeName = DOMAttributeNames[propName];
+        DOMProperty.getPossibleStandardName[attributeName] = propName;
+        DOMProperty.getAttributeName[propName] = attributeName;
+      } else {
+        DOMProperty.getAttributeName[propName] = lowerCased;
+      }
+
+      DOMProperty.getPropertyName[propName] =
+        DOMPropertyNames.hasOwnProperty(propName) ?
+          DOMPropertyNames[propName] :
+          propName;
+
+      if (DOMMutationMethods.hasOwnProperty(propName)) {
+        DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
+      } else {
+        DOMProperty.getMutationMethod[propName] = null;
+      }
+
+      var propConfig = Properties[propName];
+      DOMProperty.mustUseAttribute[propName] =
+        checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
+      DOMProperty.mustUseProperty[propName] =
+        checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
+      DOMProperty.hasSideEffects[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
+      DOMProperty.hasBooleanValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
+      DOMProperty.hasNumericValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
+      DOMProperty.hasPositiveNumericValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
+      DOMProperty.hasOverloadedBooleanValue[propName] =
+        checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);
+
+      ("production" !== process.env.NODE_ENV ? invariant(
+        !DOMProperty.mustUseAttribute[propName] ||
+          !DOMProperty.mustUseProperty[propName],
+        'DOMProperty: Cannot require using both attribute and property: %s',
+        propName
+      ) : invariant(!DOMProperty.mustUseAttribute[propName] ||
+        !DOMProperty.mustUseProperty[propName]));
+      ("production" !== process.env.NODE_ENV ? invariant(
+        DOMProperty.mustUseProperty[propName] ||
+          !DOMProperty.hasSideEffects[propName],
+        'DOMProperty: Properties that have side effects must use property: %s',
+        propName
+      ) : invariant(DOMProperty.mustUseProperty[propName] ||
+        !DOMProperty.hasSideEffects[propName]));
+      ("production" !== process.env.NODE_ENV ? invariant(
+        !!DOMProperty.hasBooleanValue[propName] +
+          !!DOMProperty.hasNumericValue[propName] +
+          !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
+        'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
+        'numeric value, but not a combination: %s',
+        propName
+      ) : invariant(!!DOMProperty.hasBooleanValue[propName] +
+        !!DOMProperty.hasNumericValue[propName] +
+        !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
+    }
+  }
+};
+var defaultValueCache = {};
+
+/**
+ * DOMProperty exports lookup objects that can be used like functions:
+ *
+ *   > DOMProperty.isValid['id']
+ *   true
+ *   > DOMProperty.isValid['foobar']
+ *   undefined
+ *
+ * Although this may be confusing, it performs better in general.
+ *
+ * @see http://jsperf.com/key-exists
+ * @see http://jsperf.com/key-missing
+ */
+var DOMProperty = {
+
+  ID_ATTRIBUTE_NAME: 'data-reactid',
+
+  /**
+   * Checks whether a property name is a standard property.
+   * @type {Object}
+   */
+  isStandardName: {},
+
+  /**
+   * Mapping from lowercase property names to the properly cased version, used
+   * to warn in the case of missing properties.
+   * @type {Object}
+   */
+  getPossibleStandardName: {},
+
+  /**
+   * Mapping from normalized names to attribute names that differ. Attribute
+   * names are used when rendering markup or with `*Attribute()`.
+   * @type {Object}
+   */
+  getAttributeName: {},
+
+  /**
+   * Mapping from normalized names to properties on DOM node instances.
+   * (This includes properties that mutate due to external factors.)
+   * @type {Object}
+   */
+  getPropertyName: {},
+
+  /**
+   * Mapping from normalized names to mutation methods. This will only exist if
+   * mutation cannot be set simply by the property or `setAttribute()`.
+   * @type {Object}
+   */
+  getMutationMethod: {},
+
+  /**
+   * Whether the property must be accessed and mutated as an object property.
+   * @type {Object}
+   */
+  mustUseAttribute: {},
+
+  /**
+   * Whether the property must be accessed and mutated using `*Attribute()`.
+   * (This includes anything that fails `<propName> in <element>`.)
+   * @type {Object}
+   */
+  mustUseProperty: {},
+
+  /**
+   * Whether or not setting a value causes side effects such as triggering
+   * resources to be loaded or text selection changes. We must ensure that
+   * the value is only set if it has changed.
+   * @type {Object}
+   */
+  hasSideEffects: {},
+
+  /**
+   * Whether the property should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasBooleanValue: {},
+
+  /**
+   * Whether the property must be numeric or parse as a
+   * numeric and should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasNumericValue: {},
+
+  /**
+   * Whether the property must be positive numeric or parse as a positive
+   * numeric and should be removed when set to a falsey value.
+   * @type {Object}
+   */
+  hasPositiveNumericValue: {},
+
+  /**
+   * Whether the property can be used as a flag as well as with a value. Removed
+   * when strictly equal to false; present without a value when strictly equal
+   * to true; present with a value otherwise.
+   * @type {Object}
+   */
+  hasOverloadedBooleanValue: {},
+
+  /**
+   * All of the isCustomAttribute() functions that have been injected.
+   */
+  _isCustomAttributeFunctions: [],
+
+  /**
+   * Checks whether a property name is a custom attribute.
+   * @method
+   */
+  isCustomAttribute: function(attributeName) {
+    for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
+      var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
+      if (isCustomAttributeFn(attributeName)) {
+        return true;
+      }
+    }
+    return false;
+  },
+
+  /**
+   * Returns the default property value for a DOM property (i.e., not an
+   * attribute). Most default values are '' or false, but not all. Worse yet,
+   * some (in particular, `type`) vary depending on the type of element.
+   *
+   * TODO: Is it better to grab all the possible properties when creating an
+   * element to avoid having to create the same element twice?
+   */
+  getDefaultValueForProperty: function(nodeName, prop) {
+    var nodeDefaults = defaultValueCache[nodeName];
+    var testElement;
+    if (!nodeDefaults) {
+      defaultValueCache[nodeName] = nodeDefaults = {};
+    }
+    if (!(prop in nodeDefaults)) {
+      testElement = document.createElement(nodeName);
+      nodeDefaults[prop] = testElement[prop];
+    }
+    return nodeDefaults[prop];
+  },
+
+  injection: DOMPropertyInjection
+};
+
+module.exports = DOMProperty;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],11:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DOMPropertyOperations
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+
+var quoteAttributeValueForBrowser = require("./quoteAttributeValueForBrowser");
+var warning = require("./warning");
+
+function shouldIgnoreValue(name, value) {
+  return value == null ||
+    (DOMProperty.hasBooleanValue[name] && !value) ||
+    (DOMProperty.hasNumericValue[name] && isNaN(value)) ||
+    (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) ||
+    (DOMProperty.hasOverloadedBooleanValue[name] && value === false);
+}
+
+if ("production" !== process.env.NODE_ENV) {
+  var reactProps = {
+    children: true,
+    dangerouslySetInnerHTML: true,
+    key: true,
+    ref: true
+  };
+  var warnedProperties = {};
+
+  var warnUnknownProperty = function(name) {
+    if (reactProps.hasOwnProperty(name) && reactProps[name] ||
+        warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
+      return;
+    }
+
+    warnedProperties[name] = true;
+    var lowerCasedName = name.toLowerCase();
+
+    // data-* attributes should be lowercase; suggest the lowercase version
+    var standardName = (
+      DOMProperty.isCustomAttribute(lowerCasedName) ?
+        lowerCasedName :
+      DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
+        DOMProperty.getPossibleStandardName[lowerCasedName] :
+        null
+    );
+
+    // For now, only warn when we have a suggested correction. This prevents
+    // logging too much when using transferPropsTo.
+    ("production" !== process.env.NODE_ENV ? warning(
+      standardName == null,
+      'Unknown DOM property %s. Did you mean %s?',
+      name,
+      standardName
+    ) : null);
+
+  };
+}
+
+/**
+ * Operations for dealing with DOM properties.
+ */
+var DOMPropertyOperations = {
+
+  /**
+   * Creates markup for the ID property.
+   *
+   * @param {string} id Unescaped ID.
+   * @return {string} Markup string.
+   */
+  createMarkupForID: function(id) {
+    return DOMProperty.ID_ATTRIBUTE_NAME + '=' +
+      quoteAttributeValueForBrowser(id);
+  },
+
+  /**
+   * Creates markup for a property.
+   *
+   * @param {string} name
+   * @param {*} value
+   * @return {?string} Markup string, or null if the property was invalid.
+   */
+  createMarkupForProperty: function(name, value) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      if (shouldIgnoreValue(name, value)) {
+        return '';
+      }
+      var attributeName = DOMProperty.getAttributeName[name];
+      if (DOMProperty.hasBooleanValue[name] ||
+          (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
+        return attributeName;
+      }
+      return attributeName + '=' + quoteAttributeValueForBrowser(value);
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      if (value == null) {
+        return '';
+      }
+      return name + '=' + quoteAttributeValueForBrowser(value);
+    } else if ("production" !== process.env.NODE_ENV) {
+      warnUnknownProperty(name);
+    }
+    return null;
+  },
+
+  /**
+   * Sets the value for a property on a node.
+   *
+   * @param {DOMElement} node
+   * @param {string} name
+   * @param {*} value
+   */
+  setValueForProperty: function(node, name, value) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      var mutationMethod = DOMProperty.getMutationMethod[name];
+      if (mutationMethod) {
+        mutationMethod(node, value);
+      } else if (shouldIgnoreValue(name, value)) {
+        this.deleteValueForProperty(node, name);
+      } else if (DOMProperty.mustUseAttribute[name]) {
+        // `setAttribute` with objects becomes only `[object]` in IE8/9,
+        // ('' + value) makes it output the correct toString()-value.
+        node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
+      } else {
+        var propName = DOMProperty.getPropertyName[name];
+        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
+        // property type before comparing; only `value` does and is string.
+        if (!DOMProperty.hasSideEffects[name] ||
+            ('' + node[propName]) !== ('' + value)) {
+          // Contrary to `setAttribute`, object properties are properly
+          // `toString`ed by IE8/9.
+          node[propName] = value;
+        }
+      }
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      if (value == null) {
+        node.removeAttribute(name);
+      } else {
+        node.setAttribute(name, '' + value);
+      }
+    } else if ("production" !== process.env.NODE_ENV) {
+      warnUnknownProperty(name);
+    }
+  },
+
+  /**
+   * Deletes the value for a property on a node.
+   *
+   * @param {DOMElement} node
+   * @param {string} name
+   */
+  deleteValueForProperty: function(node, name) {
+    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
+        DOMProperty.isStandardName[name]) {
+      var mutationMethod = DOMProperty.getMutationMethod[name];
+      if (mutationMethod) {
+        mutationMethod(node, undefined);
+      } else if (DOMProperty.mustUseAttribute[name]) {
+        node.removeAttribute(DOMProperty.getAttributeName[name]);
+      } else {
+        var propName = DOMProperty.getPropertyName[name];
+        var defaultValue = DOMProperty.getDefaultValueForProperty(
+          node.nodeName,
+          propName
+        );
+        if (!DOMProperty.hasSideEffects[name] ||
+            ('' + node[propName]) !== defaultValue) {
+          node[propName] = defaultValue;
+        }
+      }
+    } else if (DOMProperty.isCustomAttribute(name)) {
+      node.removeAttribute(name);
+    } else if ("production" !== process.env.NODE_ENV) {
+      warnUnknownProperty(name);
+    }
+  }
+
+};
+
+module.exports = DOMPropertyOperations;
+
+}).call(this,require('_process'))
+},{"./DOMProperty":10,"./quoteAttributeValueForBrowser":148,"./warning":155,"_process":157}],12:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Danger
+ * @typechecks static-only
+ */
+
+/*jslint evil: true, sub: true */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var createNodesFromMarkup = require("./createNodesFromMarkup");
+var emptyFunction = require("./emptyFunction");
+var getMarkupWrap = require("./getMarkupWrap");
+var invariant = require("./invariant");
+
+var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
+var RESULT_INDEX_ATTR = 'data-danger-index';
+
+/**
+ * Extracts the `nodeName` from a string of markup.
+ *
+ * NOTE: Extracting the `nodeName` does not require a regular expression match
+ * because we make assumptions about React-generated markup (i.e. there are no
+ * spaces surrounding the opening tag and there is at least one attribute).
+ *
+ * @param {string} markup String of markup.
+ * @return {string} Node name of the supplied markup.
+ * @see http://jsperf.com/extract-nodename
+ */
+function getNodeName(markup) {
+  return markup.substring(1, markup.indexOf(' '));
+}
+
+var Danger = {
+
+  /**
+   * Renders markup into an array of nodes. The markup is expected to render
+   * into a list of root nodes. Also, the length of `resultList` and
+   * `markupList` should be the same.
+   *
+   * @param {array<string>} markupList List of markup strings to render.
+   * @return {array<DOMElement>} List of rendered nodes.
+   * @internal
+   */
+  dangerouslyRenderMarkup: function(markupList) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ExecutionEnvironment.canUseDOM,
+      'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +
+      'thread. Make sure `window` and `document` are available globally ' +
+      'before requiring React when unit testing or use ' +
+      'React.renderToString for server rendering.'
+    ) : invariant(ExecutionEnvironment.canUseDOM));
+    var nodeName;
+    var markupByNodeName = {};
+    // Group markup by `nodeName` if a wrap is necessary, else by '*'.
+    for (var i = 0; i < markupList.length; i++) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        markupList[i],
+        'dangerouslyRenderMarkup(...): Missing markup.'
+      ) : invariant(markupList[i]));
+      nodeName = getNodeName(markupList[i]);
+      nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
+      markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
+      markupByNodeName[nodeName][i] = markupList[i];
+    }
+    var resultList = [];
+    var resultListAssignmentCount = 0;
+    for (nodeName in markupByNodeName) {
+      if (!markupByNodeName.hasOwnProperty(nodeName)) {
+        continue;
+      }
+      var markupListByNodeName = markupByNodeName[nodeName];
+
+      // This for-in loop skips the holes of the sparse array. The order of
+      // iteration should follow the order of assignment, which happens to match
+      // numerical index order, but we don't rely on that.
+      var resultIndex;
+      for (resultIndex in markupListByNodeName) {
+        if (markupListByNodeName.hasOwnProperty(resultIndex)) {
+          var markup = markupListByNodeName[resultIndex];
+
+          // Push the requested markup with an additional RESULT_INDEX_ATTR
+          // attribute.  If the markup does not start with a < character, it
+          // will be discarded below (with an appropriate console.error).
+          markupListByNodeName[resultIndex] = markup.replace(
+            OPEN_TAG_NAME_EXP,
+            // This index will be parsed back out below.
+            '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
+          );
+        }
+      }
+
+      // Render each group of markup with similar wrapping `nodeName`.
+      var renderNodes = createNodesFromMarkup(
+        markupListByNodeName.join(''),
+        emptyFunction // Do nothing special with <script> tags.
+      );
+
+      for (var j = 0; j < renderNodes.length; ++j) {
+        var renderNode = renderNodes[j];
+        if (renderNode.hasAttribute &&
+            renderNode.hasAttribute(RESULT_INDEX_ATTR)) {
+
+          resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
+          renderNode.removeAttribute(RESULT_INDEX_ATTR);
+
+          ("production" !== process.env.NODE_ENV ? invariant(
+            !resultList.hasOwnProperty(resultIndex),
+            'Danger: Assigning to an already-occupied result index.'
+          ) : invariant(!resultList.hasOwnProperty(resultIndex)));
+
+          resultList[resultIndex] = renderNode;
+
+          // This should match resultList.length and markupList.length when
+          // we're done.
+          resultListAssignmentCount += 1;
+
+        } else if ("production" !== process.env.NODE_ENV) {
+          console.error(
+            'Danger: Discarding unexpected node:',
+            renderNode
+          );
+        }
+      }
+    }
+
+    // Although resultList was populated out of order, it should now be a dense
+    // array.
+    ("production" !== process.env.NODE_ENV ? invariant(
+      resultListAssignmentCount === resultList.length,
+      'Danger: Did not assign to every index of resultList.'
+    ) : invariant(resultListAssignmentCount === resultList.length));
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      resultList.length === markupList.length,
+      'Danger: Expected markup to render %s nodes, but rendered %s.',
+      markupList.length,
+      resultList.length
+    ) : invariant(resultList.length === markupList.length));
+
+    return resultList;
+  },
+
+  /**
+   * Replaces a node with a string of markup at its current position within its
+   * parent. The markup must render into a single root node.
+   *
+   * @param {DOMElement} oldChild Child node to replace.
+   * @param {string} markup Markup to render in place of the child node.
+   * @internal
+   */
+  dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ExecutionEnvironment.canUseDOM,
+      'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +
+      'worker thread. Make sure `window` and `document` are available ' +
+      'globally before requiring React when unit testing or use ' +
+      'React.renderToString for server rendering.'
+    ) : invariant(ExecutionEnvironment.canUseDOM));
+    ("production" !== process.env.NODE_ENV ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
+    ("production" !== process.env.NODE_ENV ? invariant(
+      oldChild.tagName.toLowerCase() !== 'html',
+      'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
+      '<html> node. This is because browser quirks make this unreliable ' +
+      'and/or slow. If you want to render to the root you must use ' +
+      'server rendering. See React.renderToString().'
+    ) : invariant(oldChild.tagName.toLowerCase() !== 'html'));
+
+    var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
+    oldChild.parentNode.replaceChild(newChild, oldChild);
+  }
+
+};
+
+module.exports = Danger;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":21,"./createNodesFromMarkup":113,"./emptyFunction":115,"./getMarkupWrap":128,"./invariant":136,"_process":157}],13:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule DefaultEventPluginOrder
+ */
+
+'use strict';
+
+var keyOf = require("./keyOf");
+
+/**
+ * Module that is injectable into `EventPluginHub`, that specifies a
+ * deterministic ordering of `EventPlugin`s. A convenient way to reason about
+ * plugins, without having to package every one of them. This is better than
+ * having plugins be ordered in the same order that they are injected because
+ * that ordering would be influenced by the packaging order.
+ * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
+ * preventing default on events is convenient in `SimpleEventPlugin` handlers.
+ */
+var DefaultEventPluginOrder = [
+  keyOf({ResponderEventPlugin: null}),
+  keyOf({SimpleEventPlugin: null}),
+  keyOf({TapEventPlugin: null}),
+  keyOf({EnterLeaveEventPlugin: null}),
+  keyOf({ChangeEventPlugin: null}),
+  keyOf({SelectEventPlugin: null}),
+  keyOf({BeforeInputEventPlugin: null}),
+  keyOf({AnalyticsEventPlugin: null}),
+  keyOf({MobileSafariClickEventPlugin: null})
+];
+
+module.exports = DefaultEventPluginOrder;
+
+},{"./keyOf":142}],14:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EnterLeaveEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+var ReactMount = require("./ReactMount");
+var keyOf = require("./keyOf");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+var getFirstReactDOM = ReactMount.getFirstReactDOM;
+
+var eventTypes = {
+  mouseEnter: {
+    registrationName: keyOf({onMouseEnter: null}),
+    dependencies: [
+      topLevelTypes.topMouseOut,
+      topLevelTypes.topMouseOver
+    ]
+  },
+  mouseLeave: {
+    registrationName: keyOf({onMouseLeave: null}),
+    dependencies: [
+      topLevelTypes.topMouseOut,
+      topLevelTypes.topMouseOver
+    ]
+  }
+};
+
+var extractedEvents = [null, null];
+
+var EnterLeaveEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * For almost every interaction we care about, there will be both a top-level
+   * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
+   * we do not extract duplicate events. However, moving the mouse into the
+   * browser from outside will not fire a `mouseout` event. In this case, we use
+   * the `mouseover` top-level event.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    if (topLevelType === topLevelTypes.topMouseOver &&
+        (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
+      return null;
+    }
+    if (topLevelType !== topLevelTypes.topMouseOut &&
+        topLevelType !== topLevelTypes.topMouseOver) {
+      // Must not be a mouse in or mouse out - ignoring.
+      return null;
+    }
+
+    var win;
+    if (topLevelTarget.window === topLevelTarget) {
+      // `topLevelTarget` is probably a window object.
+      win = topLevelTarget;
+    } else {
+      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+      var doc = topLevelTarget.ownerDocument;
+      if (doc) {
+        win = doc.defaultView || doc.parentWindow;
+      } else {
+        win = window;
+      }
+    }
+
+    var from, to;
+    if (topLevelType === topLevelTypes.topMouseOut) {
+      from = topLevelTarget;
+      to =
+        getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
+        win;
+    } else {
+      from = win;
+      to = topLevelTarget;
+    }
+
+    if (from === to) {
+      // Nothing pertains to our managed components.
+      return null;
+    }
+
+    var fromID = from ? ReactMount.getID(from) : '';
+    var toID = to ? ReactMount.getID(to) : '';
+
+    var leave = SyntheticMouseEvent.getPooled(
+      eventTypes.mouseLeave,
+      fromID,
+      nativeEvent
+    );
+    leave.type = 'mouseleave';
+    leave.target = from;
+    leave.relatedTarget = to;
+
+    var enter = SyntheticMouseEvent.getPooled(
+      eventTypes.mouseEnter,
+      toID,
+      nativeEvent
+    );
+    enter.type = 'mouseenter';
+    enter.target = to;
+    enter.relatedTarget = from;
+
+    EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);
+
+    extractedEvents[0] = leave;
+    extractedEvents[1] = enter;
+
+    return extractedEvents;
+  }
+
+};
+
+module.exports = EnterLeaveEventPlugin;
+
+},{"./EventConstants":15,"./EventPropagators":20,"./ReactMount":71,"./SyntheticMouseEvent":100,"./keyOf":142}],15:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventConstants
+ */
+
+'use strict';
+
+var keyMirror = require("./keyMirror");
+
+var PropagationPhases = keyMirror({bubbled: null, captured: null});
+
+/**
+ * Types of raw signals from the browser caught at the top level.
+ */
+var topLevelTypes = keyMirror({
+  topBlur: null,
+  topChange: null,
+  topClick: null,
+  topCompositionEnd: null,
+  topCompositionStart: null,
+  topCompositionUpdate: null,
+  topContextMenu: null,
+  topCopy: null,
+  topCut: null,
+  topDoubleClick: null,
+  topDrag: null,
+  topDragEnd: null,
+  topDragEnter: null,
+  topDragExit: null,
+  topDragLeave: null,
+  topDragOver: null,
+  topDragStart: null,
+  topDrop: null,
+  topError: null,
+  topFocus: null,
+  topInput: null,
+  topKeyDown: null,
+  topKeyPress: null,
+  topKeyUp: null,
+  topLoad: null,
+  topMouseDown: null,
+  topMouseMove: null,
+  topMouseOut: null,
+  topMouseOver: null,
+  topMouseUp: null,
+  topPaste: null,
+  topReset: null,
+  topScroll: null,
+  topSelectionChange: null,
+  topSubmit: null,
+  topTextInput: null,
+  topTouchCancel: null,
+  topTouchEnd: null,
+  topTouchMove: null,
+  topTouchStart: null,
+  topWheel: null
+});
+
+var EventConstants = {
+  topLevelTypes: topLevelTypes,
+  PropagationPhases: PropagationPhases
+};
+
+module.exports = EventConstants;
+
+},{"./keyMirror":141}],16:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @providesModule EventListener
+ * @typechecks
+ */
+
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Upstream version of event listener. Does not take into account specific
+ * nature of platform.
+ */
+var EventListener = {
+  /**
+   * Listen to DOM events during the bubble phase.
+   *
+   * @param {DOMEventTarget} target DOM element to register listener on.
+   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+   * @param {function} callback Callback function.
+   * @return {object} Object with a `remove` method.
+   */
+  listen: function(target, eventType, callback) {
+    if (target.addEventListener) {
+      target.addEventListener(eventType, callback, false);
+      return {
+        remove: function() {
+          target.removeEventListener(eventType, callback, false);
+        }
+      };
+    } else if (target.attachEvent) {
+      target.attachEvent('on' + eventType, callback);
+      return {
+        remove: function() {
+          target.detachEvent('on' + eventType, callback);
+        }
+      };
+    }
+  },
+
+  /**
+   * Listen to DOM events during the capture phase.
+   *
+   * @param {DOMEventTarget} target DOM element to register listener on.
+   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
+   * @param {function} callback Callback function.
+   * @return {object} Object with a `remove` method.
+   */
+  capture: function(target, eventType, callback) {
+    if (!target.addEventListener) {
+      if ("production" !== process.env.NODE_ENV) {
+        console.error(
+          'Attempted to listen to events during the capture phase on a ' +
+          'browser that does not support the capture phase. Your application ' +
+          'will not receive some events.'
+        );
+      }
+      return {
+        remove: emptyFunction
+      };
+    } else {
+      target.addEventListener(eventType, callback, true);
+      return {
+        remove: function() {
+          target.removeEventListener(eventType, callback, true);
+        }
+      };
+    }
+  },
+
+  registerDefault: function() {}
+};
+
+module.exports = EventListener;
+
+}).call(this,require('_process'))
+},{"./emptyFunction":115,"_process":157}],17:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginHub
+ */
+
+'use strict';
+
+var EventPluginRegistry = require("./EventPluginRegistry");
+var EventPluginUtils = require("./EventPluginUtils");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+var invariant = require("./invariant");
+
+/**
+ * Internal store for event listeners
+ */
+var listenerBank = {};
+
+/**
+ * Internal queue of events that have accumulated their dispatches and are
+ * waiting to have their dispatches executed.
+ */
+var eventQueue = null;
+
+/**
+ * Dispatches an event and releases it back into the pool, unless persistent.
+ *
+ * @param {?object} event Synthetic event to be dispatched.
+ * @private
+ */
+var executeDispatchesAndRelease = function(event) {
+  if (event) {
+    var executeDispatch = EventPluginUtils.executeDispatch;
+    // Plugins can provide custom behavior when dispatching events.
+    var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
+    if (PluginModule && PluginModule.executeDispatch) {
+      executeDispatch = PluginModule.executeDispatch;
+    }
+    EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);
+
+    if (!event.isPersistent()) {
+      event.constructor.release(event);
+    }
+  }
+};
+
+/**
+ * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
+ *   hierarchy given ids of the logical DOM elements involved.
+ */
+var InstanceHandle = null;
+
+function validateInstanceHandle() {
+  var valid =
+    InstanceHandle &&
+    InstanceHandle.traverseTwoPhase &&
+    InstanceHandle.traverseEnterLeave;
+  ("production" !== process.env.NODE_ENV ? invariant(
+    valid,
+    'InstanceHandle not injected before use!'
+  ) : invariant(valid));
+}
+
+/**
+ * This is a unified interface for event plugins to be installed and configured.
+ *
+ * Event plugins can implement the following properties:
+ *
+ *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
+ *     Required. When a top-level event is fired, this method is expected to
+ *     extract synthetic events that will in turn be queued and dispatched.
+ *
+ *   `eventTypes` {object}
+ *     Optional, plugins that fire events must publish a mapping of registration
+ *     names that are used to register listeners. Values of this mapping must
+ *     be objects that contain `registrationName` or `phasedRegistrationNames`.
+ *
+ *   `executeDispatch` {function(object, function, string)}
+ *     Optional, allows plugins to override how an event gets dispatched. By
+ *     default, the listener is simply invoked.
+ *
+ * Each plugin that is injected into `EventsPluginHub` is immediately operable.
+ *
+ * @public
+ */
+var EventPluginHub = {
+
+  /**
+   * Methods for injecting dependencies.
+   */
+  injection: {
+
+    /**
+     * @param {object} InjectedMount
+     * @public
+     */
+    injectMount: EventPluginUtils.injection.injectMount,
+
+    /**
+     * @param {object} InjectedInstanceHandle
+     * @public
+     */
+    injectInstanceHandle: function(InjectedInstanceHandle) {
+      InstanceHandle = InjectedInstanceHandle;
+      if ("production" !== process.env.NODE_ENV) {
+        validateInstanceHandle();
+      }
+    },
+
+    getInstanceHandle: function() {
+      if ("production" !== process.env.NODE_ENV) {
+        validateInstanceHandle();
+      }
+      return InstanceHandle;
+    },
+
+    /**
+     * @param {array} InjectedEventPluginOrder
+     * @public
+     */
+    injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,
+
+    /**
+     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+     */
+    injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName
+
+  },
+
+  eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,
+
+  registrationNameModules: EventPluginRegistry.registrationNameModules,
+
+  /**
+   * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
+   *
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @param {?function} listener The callback to store.
+   */
+  putListener: function(id, registrationName, listener) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !listener || typeof listener === 'function',
+      'Expected %s listener to be a function, instead got type %s',
+      registrationName, typeof listener
+    ) : invariant(!listener || typeof listener === 'function'));
+
+    var bankForRegistrationName =
+      listenerBank[registrationName] || (listenerBank[registrationName] = {});
+    bankForRegistrationName[id] = listener;
+  },
+
+  /**
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @return {?function} The stored callback.
+   */
+  getListener: function(id, registrationName) {
+    var bankForRegistrationName = listenerBank[registrationName];
+    return bankForRegistrationName && bankForRegistrationName[id];
+  },
+
+  /**
+   * Deletes a listener from the registration bank.
+   *
+   * @param {string} id ID of the DOM element.
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   */
+  deleteListener: function(id, registrationName) {
+    var bankForRegistrationName = listenerBank[registrationName];
+    if (bankForRegistrationName) {
+      delete bankForRegistrationName[id];
+    }
+  },
+
+  /**
+   * Deletes all listeners for the DOM element with the supplied ID.
+   *
+   * @param {string} id ID of the DOM element.
+   */
+  deleteAllListeners: function(id) {
+    for (var registrationName in listenerBank) {
+      delete listenerBank[registrationName][id];
+    }
+  },
+
+  /**
+   * Allows registered plugins an opportunity to extract events from top-level
+   * native browser events.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @internal
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var events;
+    var plugins = EventPluginRegistry.plugins;
+    for (var i = 0, l = plugins.length; i < l; i++) {
+      // Not every plugin in the ordering may be loaded at runtime.
+      var possiblePlugin = plugins[i];
+      if (possiblePlugin) {
+        var extractedEvents = possiblePlugin.extractEvents(
+          topLevelType,
+          topLevelTarget,
+          topLevelTargetID,
+          nativeEvent
+        );
+        if (extractedEvents) {
+          events = accumulateInto(events, extractedEvents);
+        }
+      }
+    }
+    return events;
+  },
+
+  /**
+   * Enqueues a synthetic event that should be dispatched when
+   * `processEventQueue` is invoked.
+   *
+   * @param {*} events An accumulation of synthetic events.
+   * @internal
+   */
+  enqueueEvents: function(events) {
+    if (events) {
+      eventQueue = accumulateInto(eventQueue, events);
+    }
+  },
+
+  /**
+   * Dispatches all synthetic events on the event queue.
+   *
+   * @internal
+   */
+  processEventQueue: function() {
+    // Set `eventQueue` to null before processing it so that we can tell if more
+    // events get enqueued while processing.
+    var processingEventQueue = eventQueue;
+    eventQueue = null;
+    forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !eventQueue,
+      'processEventQueue(): Additional events were enqueued while processing ' +
+      'an event queue. Support for this has not yet been implemented.'
+    ) : invariant(!eventQueue));
+  },
+
+  /**
+   * These are needed for tests only. Do not use!
+   */
+  __purge: function() {
+    listenerBank = {};
+  },
+
+  __getListenerBank: function() {
+    return listenerBank;
+  }
+
+};
+
+module.exports = EventPluginHub;
+
+}).call(this,require('_process'))
+},{"./EventPluginRegistry":18,"./EventPluginUtils":19,"./accumulateInto":106,"./forEachAccumulated":121,"./invariant":136,"_process":157}],18:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginRegistry
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ * Injectable ordering of event plugins.
+ */
+var EventPluginOrder = null;
+
+/**
+ * Injectable mapping from names to event plugin modules.
+ */
+var namesToPlugins = {};
+
+/**
+ * Recomputes the plugin list using the injected plugins and plugin ordering.
+ *
+ * @private
+ */
+function recomputePluginOrdering() {
+  if (!EventPluginOrder) {
+    // Wait until an `EventPluginOrder` is injected.
+    return;
+  }
+  for (var pluginName in namesToPlugins) {
+    var PluginModule = namesToPlugins[pluginName];
+    var pluginIndex = EventPluginOrder.indexOf(pluginName);
+    ("production" !== process.env.NODE_ENV ? invariant(
+      pluginIndex > -1,
+      'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
+      'the plugin ordering, `%s`.',
+      pluginName
+    ) : invariant(pluginIndex > -1));
+    if (EventPluginRegistry.plugins[pluginIndex]) {
+      continue;
+    }
+    ("production" !== process.env.NODE_ENV ? invariant(
+      PluginModule.extractEvents,
+      'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
+      'method, but `%s` does not.',
+      pluginName
+    ) : invariant(PluginModule.extractEvents));
+    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
+    var publishedEvents = PluginModule.eventTypes;
+    for (var eventName in publishedEvents) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        publishEventForPlugin(
+          publishedEvents[eventName],
+          PluginModule,
+          eventName
+        ),
+        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
+        eventName,
+        pluginName
+      ) : invariant(publishEventForPlugin(
+        publishedEvents[eventName],
+        PluginModule,
+        eventName
+      )));
+    }
+  }
+}
+
+/**
+ * Publishes an event so that it can be dispatched by the supplied plugin.
+ *
+ * @param {object} dispatchConfig Dispatch configuration for the event.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @return {boolean} True if the event was successfully published.
+ * @private
+ */
+function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+    'event name, `%s`.',
+    eventName
+  ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName)));
+  EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
+
+  var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
+  if (phasedRegistrationNames) {
+    for (var phaseName in phasedRegistrationNames) {
+      if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
+        var phasedRegistrationName = phasedRegistrationNames[phaseName];
+        publishRegistrationName(
+          phasedRegistrationName,
+          PluginModule,
+          eventName
+        );
+      }
+    }
+    return true;
+  } else if (dispatchConfig.registrationName) {
+    publishRegistrationName(
+      dispatchConfig.registrationName,
+      PluginModule,
+      eventName
+    );
+    return true;
+  }
+  return false;
+}
+
+/**
+ * Publishes a registration name that is used to identify dispatched events and
+ * can be used with `EventPluginHub.putListener` to register listeners.
+ *
+ * @param {string} registrationName Registration name to add.
+ * @param {object} PluginModule Plugin publishing the event.
+ * @private
+ */
+function publishRegistrationName(registrationName, PluginModule, eventName) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    !EventPluginRegistry.registrationNameModules[registrationName],
+    'EventPluginHub: More than one plugin attempted to publish the same ' +
+    'registration name, `%s`.',
+    registrationName
+  ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
+  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
+  EventPluginRegistry.registrationNameDependencies[registrationName] =
+    PluginModule.eventTypes[eventName].dependencies;
+}
+
+/**
+ * Registers plugins so that they can extract and dispatch events.
+ *
+ * @see {EventPluginHub}
+ */
+var EventPluginRegistry = {
+
+  /**
+   * Ordered list of injected plugins.
+   */
+  plugins: [],
+
+  /**
+   * Mapping from event name to dispatch config
+   */
+  eventNameDispatchConfigs: {},
+
+  /**
+   * Mapping from registration name to plugin module
+   */
+  registrationNameModules: {},
+
+  /**
+   * Mapping from registration name to event name
+   */
+  registrationNameDependencies: {},
+
+  /**
+   * Injects an ordering of plugins (by plugin name). This allows the ordering
+   * to be decoupled from injection of the actual plugins so that ordering is
+   * always deterministic regardless of packaging, on-the-fly injection, etc.
+   *
+   * @param {array} InjectedEventPluginOrder
+   * @internal
+   * @see {EventPluginHub.injection.injectEventPluginOrder}
+   */
+  injectEventPluginOrder: function(InjectedEventPluginOrder) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !EventPluginOrder,
+      'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
+      'once. You are likely trying to load more than one copy of React.'
+    ) : invariant(!EventPluginOrder));
+    // Clone the ordering so it cannot be dynamically mutated.
+    EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
+    recomputePluginOrdering();
+  },
+
+  /**
+   * Injects plugins to be used by `EventPluginHub`. The plugin names must be
+   * in the ordering injected by `injectEventPluginOrder`.
+   *
+   * Plugins can be injected as part of page initialization or on-the-fly.
+   *
+   * @param {object} injectedNamesToPlugins Map from names to plugin modules.
+   * @internal
+   * @see {EventPluginHub.injection.injectEventPluginsByName}
+   */
+  injectEventPluginsByName: function(injectedNamesToPlugins) {
+    var isOrderingDirty = false;
+    for (var pluginName in injectedNamesToPlugins) {
+      if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
+        continue;
+      }
+      var PluginModule = injectedNamesToPlugins[pluginName];
+      if (!namesToPlugins.hasOwnProperty(pluginName) ||
+          namesToPlugins[pluginName] !== PluginModule) {
+        ("production" !== process.env.NODE_ENV ? invariant(
+          !namesToPlugins[pluginName],
+          'EventPluginRegistry: Cannot inject two different event plugins ' +
+          'using the same name, `%s`.',
+          pluginName
+        ) : invariant(!namesToPlugins[pluginName]));
+        namesToPlugins[pluginName] = PluginModule;
+        isOrderingDirty = true;
+      }
+    }
+    if (isOrderingDirty) {
+      recomputePluginOrdering();
+    }
+  },
+
+  /**
+   * Looks up the plugin for the supplied event.
+   *
+   * @param {object} event A synthetic event.
+   * @return {?object} The plugin that created the supplied event.
+   * @internal
+   */
+  getPluginModuleForEvent: function(event) {
+    var dispatchConfig = event.dispatchConfig;
+    if (dispatchConfig.registrationName) {
+      return EventPluginRegistry.registrationNameModules[
+        dispatchConfig.registrationName
+      ] || null;
+    }
+    for (var phase in dispatchConfig.phasedRegistrationNames) {
+      if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
+        continue;
+      }
+      var PluginModule = EventPluginRegistry.registrationNameModules[
+        dispatchConfig.phasedRegistrationNames[phase]
+      ];
+      if (PluginModule) {
+        return PluginModule;
+      }
+    }
+    return null;
+  },
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _resetEventPlugins: function() {
+    EventPluginOrder = null;
+    for (var pluginName in namesToPlugins) {
+      if (namesToPlugins.hasOwnProperty(pluginName)) {
+        delete namesToPlugins[pluginName];
+      }
+    }
+    EventPluginRegistry.plugins.length = 0;
+
+    var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
+    for (var eventName in eventNameDispatchConfigs) {
+      if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
+        delete eventNameDispatchConfigs[eventName];
+      }
+    }
+
+    var registrationNameModules = EventPluginRegistry.registrationNameModules;
+    for (var registrationName in registrationNameModules) {
+      if (registrationNameModules.hasOwnProperty(registrationName)) {
+        delete registrationNameModules[registrationName];
+      }
+    }
+  }
+
+};
+
+module.exports = EventPluginRegistry;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],19:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPluginUtils
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+
+var invariant = require("./invariant");
+
+/**
+ * Injected dependencies:
+ */
+
+/**
+ * - `Mount`: [required] Module that can convert between React dom IDs and
+ *   actual node references.
+ */
+var injection = {
+  Mount: null,
+  injectMount: function(InjectedMount) {
+    injection.Mount = InjectedMount;
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        InjectedMount && InjectedMount.getNode,
+        'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
+        'is missing getNode.'
+      ) : invariant(InjectedMount && InjectedMount.getNode));
+    }
+  }
+};
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+function isEndish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseUp ||
+         topLevelType === topLevelTypes.topTouchEnd ||
+         topLevelType === topLevelTypes.topTouchCancel;
+}
+
+function isMoveish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseMove ||
+         topLevelType === topLevelTypes.topTouchMove;
+}
+function isStartish(topLevelType) {
+  return topLevelType === topLevelTypes.topMouseDown ||
+         topLevelType === topLevelTypes.topTouchStart;
+}
+
+
+var validateEventDispatches;
+if ("production" !== process.env.NODE_ENV) {
+  validateEventDispatches = function(event) {
+    var dispatchListeners = event._dispatchListeners;
+    var dispatchIDs = event._dispatchIDs;
+
+    var listenersIsArr = Array.isArray(dispatchListeners);
+    var idsIsArr = Array.isArray(dispatchIDs);
+    var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
+    var listenersLen = listenersIsArr ?
+      dispatchListeners.length :
+      dispatchListeners ? 1 : 0;
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      idsIsArr === listenersIsArr && IDsLen === listenersLen,
+      'EventPluginUtils: Invalid `event`.'
+    ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
+  };
+}
+
+/**
+ * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
+ * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
+ * kept separate to conserve memory.
+ */
+function forEachEventDispatch(event, cb) {
+  var dispatchListeners = event._dispatchListeners;
+  var dispatchIDs = event._dispatchIDs;
+  if ("production" !== process.env.NODE_ENV) {
+    validateEventDispatches(event);
+  }
+  if (Array.isArray(dispatchListeners)) {
+    for (var i = 0; i < dispatchListeners.length; i++) {
+      if (event.isPropagationStopped()) {
+        break;
+      }
+      // Listeners and IDs are two parallel arrays that are always in sync.
+      cb(event, dispatchListeners[i], dispatchIDs[i]);
+    }
+  } else if (dispatchListeners) {
+    cb(event, dispatchListeners, dispatchIDs);
+  }
+}
+
+/**
+ * Default implementation of PluginModule.executeDispatch().
+ * @param {SyntheticEvent} SyntheticEvent to handle
+ * @param {function} Application-level callback
+ * @param {string} domID DOM id to pass to the callback.
+ */
+function executeDispatch(event, listener, domID) {
+  event.currentTarget = injection.Mount.getNode(domID);
+  var returnValue = listener(event, domID);
+  event.currentTarget = null;
+  return returnValue;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches.
+ */
+function executeDispatchesInOrder(event, cb) {
+  forEachEventDispatch(event, cb);
+  event._dispatchListeners = null;
+  event._dispatchIDs = null;
+}
+
+/**
+ * Standard/simple iteration through an event's collected dispatches, but stops
+ * at the first dispatch execution returning true, and returns that id.
+ *
+ * @return id of the first dispatch execution who's listener returns true, or
+ * null if no listener returned true.
+ */
+function executeDispatchesInOrderStopAtTrueImpl(event) {
+  var dispatchListeners = event._dispatchListeners;
+  var dispatchIDs = event._dispatchIDs;
+  if ("production" !== process.env.NODE_ENV) {
+    validateEventDispatches(event);
+  }
+  if (Array.isArray(dispatchListeners)) {
+    for (var i = 0; i < dispatchListeners.length; i++) {
+      if (event.isPropagationStopped()) {
+        break;
+      }
+      // Listeners and IDs are two parallel arrays that are always in sync.
+      if (dispatchListeners[i](event, dispatchIDs[i])) {
+        return dispatchIDs[i];
+      }
+    }
+  } else if (dispatchListeners) {
+    if (dispatchListeners(event, dispatchIDs)) {
+      return dispatchIDs;
+    }
+  }
+  return null;
+}
+
+/**
+ * @see executeDispatchesInOrderStopAtTrueImpl
+ */
+function executeDispatchesInOrderStopAtTrue(event) {
+  var ret = executeDispatchesInOrderStopAtTrueImpl(event);
+  event._dispatchIDs = null;
+  event._dispatchListeners = null;
+  return ret;
+}
+
+/**
+ * Execution of a "direct" dispatch - there must be at most one dispatch
+ * accumulated on the event or it is considered an error. It doesn't really make
+ * sense for an event with multiple dispatches (bubbled) to keep track of the
+ * return values at each dispatch execution, but it does tend to make sense when
+ * dealing with "direct" dispatches.
+ *
+ * @return The return value of executing the single dispatch.
+ */
+function executeDirectDispatch(event) {
+  if ("production" !== process.env.NODE_ENV) {
+    validateEventDispatches(event);
+  }
+  var dispatchListener = event._dispatchListeners;
+  var dispatchID = event._dispatchIDs;
+  ("production" !== process.env.NODE_ENV ? invariant(
+    !Array.isArray(dispatchListener),
+    'executeDirectDispatch(...): Invalid `event`.'
+  ) : invariant(!Array.isArray(dispatchListener)));
+  var res = dispatchListener ?
+    dispatchListener(event, dispatchID) :
+    null;
+  event._dispatchListeners = null;
+  event._dispatchIDs = null;
+  return res;
+}
+
+/**
+ * @param {SyntheticEvent} event
+ * @return {bool} True iff number of dispatches accumulated is greater than 0.
+ */
+function hasDispatches(event) {
+  return !!event._dispatchListeners;
+}
+
+/**
+ * General utilities that are useful in creating custom Event Plugins.
+ */
+var EventPluginUtils = {
+  isEndish: isEndish,
+  isMoveish: isMoveish,
+  isStartish: isStartish,
+
+  executeDirectDispatch: executeDirectDispatch,
+  executeDispatch: executeDispatch,
+  executeDispatchesInOrder: executeDispatchesInOrder,
+  executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
+  hasDispatches: hasDispatches,
+  injection: injection,
+  useTouchEvents: false
+};
+
+module.exports = EventPluginUtils;
+
+}).call(this,require('_process'))
+},{"./EventConstants":15,"./invariant":136,"_process":157}],20:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule EventPropagators
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+
+var PropagationPhases = EventConstants.PropagationPhases;
+var getListener = EventPluginHub.getListener;
+
+/**
+ * Some event types have a notion of different registration names for different
+ * "phases" of propagation. This finds listeners by a given phase.
+ */
+function listenerAtPhase(id, event, propagationPhase) {
+  var registrationName =
+    event.dispatchConfig.phasedRegistrationNames[propagationPhase];
+  return getListener(id, registrationName);
+}
+
+/**
+ * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
+ * here, allows us to not have to bind or create functions for each event.
+ * Mutating the event's members allows us to not have to create a wrapping
+ * "dispatch" object that pairs the event with the listener.
+ */
+function accumulateDirectionalDispatches(domID, upwards, event) {
+  if ("production" !== process.env.NODE_ENV) {
+    if (!domID) {
+      throw new Error('Dispatching id must not be null');
+    }
+  }
+  var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
+  var listener = listenerAtPhase(domID, event, phase);
+  if (listener) {
+    event._dispatchListeners =
+      accumulateInto(event._dispatchListeners, listener);
+    event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
+  }
+}
+
+/**
+ * Collect dispatches (must be entirely collected before dispatching - see unit
+ * tests). Lazily allocate the array to conserve memory.  We must loop through
+ * each event and perform the traversal for each one. We can not perform a
+ * single traversal for the entire collection of events because each event may
+ * have a different target.
+ */
+function accumulateTwoPhaseDispatchesSingle(event) {
+  if (event && event.dispatchConfig.phasedRegistrationNames) {
+    EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
+      event.dispatchMarker,
+      accumulateDirectionalDispatches,
+      event
+    );
+  }
+}
+
+
+/**
+ * Accumulates without regard to direction, does not look for phased
+ * registration names. Same as `accumulateDirectDispatchesSingle` but without
+ * requiring that the `dispatchMarker` be the same as the dispatched ID.
+ */
+function accumulateDispatches(id, ignoredDirection, event) {
+  if (event && event.dispatchConfig.registrationName) {
+    var registrationName = event.dispatchConfig.registrationName;
+    var listener = getListener(id, registrationName);
+    if (listener) {
+      event._dispatchListeners =
+        accumulateInto(event._dispatchListeners, listener);
+      event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
+    }
+  }
+}
+
+/**
+ * Accumulates dispatches on an `SyntheticEvent`, but only for the
+ * `dispatchMarker`.
+ * @param {SyntheticEvent} event
+ */
+function accumulateDirectDispatchesSingle(event) {
+  if (event && event.dispatchConfig.registrationName) {
+    accumulateDispatches(event.dispatchMarker, null, event);
+  }
+}
+
+function accumulateTwoPhaseDispatches(events) {
+  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
+}
+
+function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
+  EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
+    fromID,
+    toID,
+    accumulateDispatches,
+    leave,
+    enter
+  );
+}
+
+
+function accumulateDirectDispatches(events) {
+  forEachAccumulated(events, accumulateDirectDispatchesSingle);
+}
+
+
+
+/**
+ * A small set of propagation patterns, each of which will accept a small amount
+ * of information, and generate a set of "dispatch ready event objects" - which
+ * are sets of events that have already been annotated with a set of dispatched
+ * listener functions/ids. The API is designed this way to discourage these
+ * propagation strategies from actually executing the dispatches, since we
+ * always want to collect the entire set of dispatches before executing event a
+ * single one.
+ *
+ * @constructor EventPropagators
+ */
+var EventPropagators = {
+  accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
+  accumulateDirectDispatches: accumulateDirectDispatches,
+  accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
+};
+
+module.exports = EventPropagators;
+
+}).call(this,require('_process'))
+},{"./EventConstants":15,"./EventPluginHub":17,"./accumulateInto":106,"./forEachAccumulated":121,"_process":157}],21:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ExecutionEnvironment
+ */
+
+/*jslint evil: true */
+
+"use strict";
+
+var canUseDOM = !!(
+  (typeof window !== 'undefined' &&
+  window.document && window.document.createElement)
+);
+
+/**
+ * Simple, lightweight module assisting with the detection and context of
+ * Worker. Helps avoid circular dependencies and allows code to reason about
+ * whether or not they are in a Worker, even if they never include the main
+ * `ReactWorker` dependency.
+ */
+var ExecutionEnvironment = {
+
+  canUseDOM: canUseDOM,
+
+  canUseWorkers: typeof Worker !== 'undefined',
+
+  canUseEventListeners:
+    canUseDOM && !!(window.addEventListener || window.attachEvent),
+
+  canUseViewport: canUseDOM && !!window.screen,
+
+  isInWorker: !canUseDOM // For now, this is true - might change in the future.
+
+};
+
+module.exports = ExecutionEnvironment;
+
+},{}],22:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule FallbackCompositionState
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+
+var assign = require("./Object.assign");
+var getTextContentAccessor = require("./getTextContentAccessor");
+
+/**
+ * This helper class stores information about text content of a target node,
+ * allowing comparison of content before and after a given event.
+ *
+ * Identify the node where selection currently begins, then observe
+ * both its text content and its current position in the DOM. Since the
+ * browser may natively replace the target node during composition, we can
+ * use its position to find its replacement.
+ *
+ * @param {DOMEventTarget} root
+ */
+function FallbackCompositionState(root) {
+  this._root = root;
+  this._startText = this.getText();
+  this._fallbackText = null;
+}
+
+assign(FallbackCompositionState.prototype, {
+  /**
+   * Get current text of input.
+   *
+   * @return {string}
+   */
+  getText: function() {
+    if ('value' in this._root) {
+      return this._root.value;
+    }
+    return this._root[getTextContentAccessor()];
+  },
+
+  /**
+   * Determine the differing substring between the initially stored
+   * text content and the current content.
+   *
+   * @return {string}
+   */
+  getData: function() {
+    if (this._fallbackText) {
+      return this._fallbackText;
+    }
+
+    var start;
+    var startValue = this._startText;
+    var startLength = startValue.length;
+    var end;
+    var endValue = this.getText();
+    var endLength = endValue.length;
+
+    for (start = 0; start < startLength; start++) {
+      if (startValue[start] !== endValue[start]) {
+        break;
+      }
+    }
+
+    var minEnd = startLength - start;
+    for (end = 1; end <= minEnd; end++) {
+      if (startValue[startLength - end] !== endValue[endLength - end]) {
+        break;
+      }
+    }
+
+    var sliceTail = end > 1 ? 1 - end : undefined;
+    this._fallbackText = endValue.slice(start, sliceTail);
+    return this._fallbackText;
+  }
+});
+
+PooledClass.addPoolingTo(FallbackCompositionState);
+
+module.exports = FallbackCompositionState;
+
+},{"./Object.assign":27,"./PooledClass":28,"./getTextContentAccessor":131}],23:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule HTMLDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
+var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
+var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
+var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
+var HAS_POSITIVE_NUMERIC_VALUE =
+  DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
+var HAS_OVERLOADED_BOOLEAN_VALUE =
+  DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;
+
+var hasSVG;
+if (ExecutionEnvironment.canUseDOM) {
+  var implementation = document.implementation;
+  hasSVG = (
+    implementation &&
+    implementation.hasFeature &&
+    implementation.hasFeature(
+      'http://www.w3.org/TR/SVG11/feature#BasicStructure',
+      '1.1'
+    )
+  );
+}
+
+
+var HTMLDOMPropertyConfig = {
+  isCustomAttribute: RegExp.prototype.test.bind(
+    /^(data|aria)-[a-z_][a-z\d_.\-]*$/
+  ),
+  Properties: {
+    /**
+     * Standard Properties
+     */
+    accept: null,
+    acceptCharset: null,
+    accessKey: null,
+    action: null,
+    allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    allowTransparency: MUST_USE_ATTRIBUTE,
+    alt: null,
+    async: HAS_BOOLEAN_VALUE,
+    autoComplete: null,
+    // autoFocus is polyfilled/normalized by AutoFocusMixin
+    // autoFocus: HAS_BOOLEAN_VALUE,
+    autoPlay: HAS_BOOLEAN_VALUE,
+    cellPadding: null,
+    cellSpacing: null,
+    charSet: MUST_USE_ATTRIBUTE,
+    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    classID: MUST_USE_ATTRIBUTE,
+    // To set className on SVG elements, it's necessary to use .setAttribute;
+    // this works on HTML elements too in all browsers except IE8. Conveniently,
+    // IE8 doesn't support SVG and so we can simply use the attribute in
+    // browsers that support SVG and the property in browsers that don't,
+    // regardless of whether the element is HTML or SVG.
+    className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
+    cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    colSpan: null,
+    content: null,
+    contentEditable: null,
+    contextMenu: MUST_USE_ATTRIBUTE,
+    controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    coords: null,
+    crossOrigin: null,
+    data: null, // For `<object />` acts as `src`.
+    dateTime: MUST_USE_ATTRIBUTE,
+    defer: HAS_BOOLEAN_VALUE,
+    dir: null,
+    disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    download: HAS_OVERLOADED_BOOLEAN_VALUE,
+    draggable: null,
+    encType: null,
+    form: MUST_USE_ATTRIBUTE,
+    formAction: MUST_USE_ATTRIBUTE,
+    formEncType: MUST_USE_ATTRIBUTE,
+    formMethod: MUST_USE_ATTRIBUTE,
+    formNoValidate: HAS_BOOLEAN_VALUE,
+    formTarget: MUST_USE_ATTRIBUTE,
+    frameBorder: MUST_USE_ATTRIBUTE,
+    headers: null,
+    height: MUST_USE_ATTRIBUTE,
+    hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    href: null,
+    hrefLang: null,
+    htmlFor: null,
+    httpEquiv: null,
+    icon: null,
+    id: MUST_USE_PROPERTY,
+    label: null,
+    lang: null,
+    list: MUST_USE_ATTRIBUTE,
+    loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    manifest: MUST_USE_ATTRIBUTE,
+    marginHeight: null,
+    marginWidth: null,
+    max: null,
+    maxLength: MUST_USE_ATTRIBUTE,
+    media: MUST_USE_ATTRIBUTE,
+    mediaGroup: null,
+    method: null,
+    min: null,
+    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    name: null,
+    noValidate: HAS_BOOLEAN_VALUE,
+    open: HAS_BOOLEAN_VALUE,
+    pattern: null,
+    placeholder: null,
+    poster: null,
+    preload: null,
+    radioGroup: null,
+    readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    rel: null,
+    required: HAS_BOOLEAN_VALUE,
+    role: MUST_USE_ATTRIBUTE,
+    rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    rowSpan: null,
+    sandbox: null,
+    scope: null,
+    scrolling: null,
+    seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+    shape: null,
+    size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
+    sizes: MUST_USE_ATTRIBUTE,
+    span: HAS_POSITIVE_NUMERIC_VALUE,
+    spellCheck: null,
+    src: null,
+    srcDoc: MUST_USE_PROPERTY,
+    srcSet: MUST_USE_ATTRIBUTE,
+    start: HAS_NUMERIC_VALUE,
+    step: null,
+    style: null,
+    tabIndex: null,
+    target: null,
+    title: null,
+    type: null,
+    useMap: null,
+    value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
+    width: MUST_USE_ATTRIBUTE,
+    wmode: MUST_USE_ATTRIBUTE,
+
+    /**
+     * Non-standard Properties
+     */
+    // autoCapitalize and autoCorrect are supported in Mobile Safari for
+    // keyboard hints.
+    autoCapitalize: null,
+    autoCorrect: null,
+    // itemProp, itemScope, itemType are for
+    // Microdata support. See http://schema.org/docs/gs.html
+    itemProp: MUST_USE_ATTRIBUTE,
+    itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
+    itemType: MUST_USE_ATTRIBUTE,
+    // itemID and itemRef are for Microdata support as well but
+    // only specified in the the WHATWG spec document. See
+    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
+    itemID: MUST_USE_ATTRIBUTE,
+    itemRef: MUST_USE_ATTRIBUTE,
+    // property is supported for OpenGraph in meta tags.
+    property: null
+  },
+  DOMAttributeNames: {
+    acceptCharset: 'accept-charset',
+    className: 'class',
+    htmlFor: 'for',
+    httpEquiv: 'http-equiv'
+  },
+  DOMPropertyNames: {
+    autoCapitalize: 'autocapitalize',
+    autoComplete: 'autocomplete',
+    autoCorrect: 'autocorrect',
+    autoFocus: 'autofocus',
+    autoPlay: 'autoplay',
+    // `encoding` is equivalent to `enctype`, IE8 lacks an `enctype` setter.
+    // http://www.w3.org/TR/html5/forms.html#dom-fs-encoding
+    encType: 'encoding',
+    hrefLang: 'hreflang',
+    radioGroup: 'radiogroup',
+    spellCheck: 'spellcheck',
+    srcDoc: 'srcdoc',
+    srcSet: 'srcset'
+  }
+};
+
+module.exports = HTMLDOMPropertyConfig;
+
+},{"./DOMProperty":10,"./ExecutionEnvironment":21}],24:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LinkedValueUtils
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactPropTypes = require("./ReactPropTypes");
+
+var invariant = require("./invariant");
+
+var hasReadOnlyValue = {
+  'button': true,
+  'checkbox': true,
+  'image': true,
+  'hidden': true,
+  'radio': true,
+  'reset': true,
+  'submit': true
+};
+
+function _assertSingleLink(input) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    input.props.checkedLink == null || input.props.valueLink == null,
+    'Cannot provide a checkedLink and a valueLink. If you want to use ' +
+    'checkedLink, you probably don\'t want to use valueLink and vice versa.'
+  ) : invariant(input.props.checkedLink == null || input.props.valueLink == null));
+}
+function _assertValueLink(input) {
+  _assertSingleLink(input);
+  ("production" !== process.env.NODE_ENV ? invariant(
+    input.props.value == null && input.props.onChange == null,
+    'Cannot provide a valueLink and a value or onChange event. If you want ' +
+    'to use value or onChange, you probably don\'t want to use valueLink.'
+  ) : invariant(input.props.value == null && input.props.onChange == null));
+}
+
+function _assertCheckedLink(input) {
+  _assertSingleLink(input);
+  ("production" !== process.env.NODE_ENV ? invariant(
+    input.props.checked == null && input.props.onChange == null,
+    'Cannot provide a checkedLink and a checked property or onChange event. ' +
+    'If you want to use checked or onChange, you probably don\'t want to ' +
+    'use checkedLink'
+  ) : invariant(input.props.checked == null && input.props.onChange == null));
+}
+
+/**
+ * @param {SyntheticEvent} e change event to handle
+ */
+function _handleLinkedValueChange(e) {
+  /*jshint validthis:true */
+  this.props.valueLink.requestChange(e.target.value);
+}
+
+/**
+  * @param {SyntheticEvent} e change event to handle
+  */
+function _handleLinkedCheckChange(e) {
+  /*jshint validthis:true */
+  this.props.checkedLink.requestChange(e.target.checked);
+}
+
+/**
+ * Provide a linked `value` attribute for controlled forms. You should not use
+ * this outside of the ReactDOM controlled form components.
+ */
+var LinkedValueUtils = {
+  Mixin: {
+    propTypes: {
+      value: function(props, propName, componentName) {
+        if (!props[propName] ||
+            hasReadOnlyValue[props.type] ||
+            props.onChange ||
+            props.readOnly ||
+            props.disabled) {
+          return null;
+        }
+        return new Error(
+          'You provided a `value` prop to a form field without an ' +
+          '`onChange` handler. This will render a read-only field. If ' +
+          'the field should be mutable use `defaultValue`. Otherwise, ' +
+          'set either `onChange` or `readOnly`.'
+        );
+      },
+      checked: function(props, propName, componentName) {
+        if (!props[propName] ||
+            props.onChange ||
+            props.readOnly ||
+            props.disabled) {
+          return null;
+        }
+        return new Error(
+          'You provided a `checked` prop to a form field without an ' +
+          '`onChange` handler. This will render a read-only field. If ' +
+          'the field should be mutable use `defaultChecked`. Otherwise, ' +
+          'set either `onChange` or `readOnly`.'
+        );
+      },
+      onChange: ReactPropTypes.func
+    }
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {*} current value of the input either from value prop or link.
+   */
+  getValue: function(input) {
+    if (input.props.valueLink) {
+      _assertValueLink(input);
+      return input.props.valueLink.value;
+    }
+    return input.props.value;
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {*} current checked status of the input either from checked prop
+   *             or link.
+   */
+  getChecked: function(input) {
+    if (input.props.checkedLink) {
+      _assertCheckedLink(input);
+      return input.props.checkedLink.value;
+    }
+    return input.props.checked;
+  },
+
+  /**
+   * @param {ReactComponent} input Form component
+   * @return {function} change callback either from onChange prop or link.
+   */
+  getOnChange: function(input) {
+    if (input.props.valueLink) {
+      _assertValueLink(input);
+      return _handleLinkedValueChange;
+    } else if (input.props.checkedLink) {
+      _assertCheckedLink(input);
+      return _handleLinkedCheckChange;
+    }
+    return input.props.onChange;
+  }
+};
+
+module.exports = LinkedValueUtils;
+
+}).call(this,require('_process'))
+},{"./ReactPropTypes":79,"./invariant":136,"_process":157}],25:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LocalEventTrapMixin
+ */
+
+'use strict';
+
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+
+var accumulateInto = require("./accumulateInto");
+var forEachAccumulated = require("./forEachAccumulated");
+var invariant = require("./invariant");
+
+function remove(event) {
+  event.remove();
+}
+
+var LocalEventTrapMixin = {
+  trapBubbledEvent:function(topLevelType, handlerBaseName) {
+    ("production" !== process.env.NODE_ENV ? invariant(this.isMounted(), 'Must be mounted to trap events') : invariant(this.isMounted()));
+    // If a component renders to null or if another component fatals and causes
+    // the state of the tree to be corrupted, `node` here can be null.
+    var node = this.getDOMNode();
+    ("production" !== process.env.NODE_ENV ? invariant(
+      node,
+      'LocalEventTrapMixin.trapBubbledEvent(...): Requires node to be rendered.'
+    ) : invariant(node));
+    var listener = ReactBrowserEventEmitter.trapBubbledEvent(
+      topLevelType,
+      handlerBaseName,
+      node
+    );
+    this._localEventListeners =
+      accumulateInto(this._localEventListeners, listener);
+  },
+
+  // trapCapturedEvent would look nearly identical. We don't implement that
+  // method because it isn't currently needed.
+
+  componentWillUnmount:function() {
+    if (this._localEventListeners) {
+      forEachAccumulated(this._localEventListeners, remove);
+    }
+  }
+};
+
+module.exports = LocalEventTrapMixin;
+
+}).call(this,require('_process'))
+},{"./ReactBrowserEventEmitter":31,"./accumulateInto":106,"./forEachAccumulated":121,"./invariant":136,"_process":157}],26:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule MobileSafariClickEventPlugin
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+
+var emptyFunction = require("./emptyFunction");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+/**
+ * Mobile Safari does not fire properly bubble click events on non-interactive
+ * elements, which means delegated click listeners do not fire. The workaround
+ * for this bug involves attaching an empty click listener on the target node.
+ *
+ * This particular plugin works around the bug by attaching an empty click
+ * listener on `touchstart` (which does fire on every element).
+ */
+var MobileSafariClickEventPlugin = {
+
+  eventTypes: null,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    if (topLevelType === topLevelTypes.topTouchStart) {
+      var target = nativeEvent.target;
+      if (target && !target.onclick) {
+        target.onclick = emptyFunction;
+      }
+    }
+  }
+
+};
+
+module.exports = MobileSafariClickEventPlugin;
+
+},{"./EventConstants":15,"./emptyFunction":115}],27:[function(require,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Object.assign
+ */
+
+// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign
+
+'use strict';
+
+function assign(target, sources) {
+  if (target == null) {
+    throw new TypeError('Object.assign target cannot be null or undefined');
+  }
+
+  var to = Object(target);
+  var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+  for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
+    var nextSource = arguments[nextIndex];
+    if (nextSource == null) {
+      continue;
+    }
+
+    var from = Object(nextSource);
+
+    // We don't currently support accessors nor proxies. Therefore this
+    // copy cannot throw. If we ever supported this then we must handle
+    // exceptions and side-effects. We don't support symbols so they won't
+    // be transferred.
+
+    for (var key in from) {
+      if (hasOwnProperty.call(from, key)) {
+        to[key] = from[key];
+      }
+    }
+  }
+
+  return to;
+}
+
+module.exports = assign;
+
+},{}],28:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule PooledClass
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ * Static poolers. Several custom versions for each potential number of
+ * arguments. A completely generic pooler is easy to implement, but would
+ * require accessing the `arguments` object. In each of these, `this` refers to
+ * the Class itself, not an instance. If any others are needed, simply add them
+ * here, or in their own files.
+ */
+var oneArgumentPooler = function(copyFieldsFrom) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, copyFieldsFrom);
+    return instance;
+  } else {
+    return new Klass(copyFieldsFrom);
+  }
+};
+
+var twoArgumentPooler = function(a1, a2) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2);
+    return instance;
+  } else {
+    return new Klass(a1, a2);
+  }
+};
+
+var threeArgumentPooler = function(a1, a2, a3) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2, a3);
+    return instance;
+  } else {
+    return new Klass(a1, a2, a3);
+  }
+};
+
+var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
+  var Klass = this;
+  if (Klass.instancePool.length) {
+    var instance = Klass.instancePool.pop();
+    Klass.call(instance, a1, a2, a3, a4, a5);
+    return instance;
+  } else {
+    return new Klass(a1, a2, a3, a4, a5);
+  }
+};
+
+var standardReleaser = function(instance) {
+  var Klass = this;
+  ("production" !== process.env.NODE_ENV ? invariant(
+    instance instanceof Klass,
+    'Trying to release an instance into a pool of a different type.'
+  ) : invariant(instance instanceof Klass));
+  if (instance.destructor) {
+    instance.destructor();
+  }
+  if (Klass.instancePool.length < Klass.poolSize) {
+    Klass.instancePool.push(instance);
+  }
+};
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+/**
+ * Augments `CopyConstructor` to be a poolable class, augmenting only the class
+ * itself (statically) not adding any prototypical fields. Any CopyConstructor
+ * you give this may have a `poolSize` property, and will look for a
+ * prototypical `destructor` on instances (optional).
+ *
+ * @param {Function} CopyConstructor Constructor that can be used to reset.
+ * @param {Function} pooler Customizable pooler.
+ */
+var addPoolingTo = function(CopyConstructor, pooler) {
+  var NewKlass = CopyConstructor;
+  NewKlass.instancePool = [];
+  NewKlass.getPooled = pooler || DEFAULT_POOLER;
+  if (!NewKlass.poolSize) {
+    NewKlass.poolSize = DEFAULT_POOL_SIZE;
+  }
+  NewKlass.release = standardReleaser;
+  return NewKlass;
+};
+
+var PooledClass = {
+  addPoolingTo: addPoolingTo,
+  oneArgumentPooler: oneArgumentPooler,
+  twoArgumentPooler: twoArgumentPooler,
+  threeArgumentPooler: threeArgumentPooler,
+  fiveArgumentPooler: fiveArgumentPooler
+};
+
+module.exports = PooledClass;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],29:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule React
+ */
+
+/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/
+
+'use strict';
+
+var EventPluginUtils = require("./EventPluginUtils");
+var ReactChildren = require("./ReactChildren");
+var ReactComponent = require("./ReactComponent");
+var ReactClass = require("./ReactClass");
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactDOM = require("./ReactDOM");
+var ReactDOMTextComponent = require("./ReactDOMTextComponent");
+var ReactDefaultInjection = require("./ReactDefaultInjection");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+var ReactPropTypes = require("./ReactPropTypes");
+var ReactReconciler = require("./ReactReconciler");
+var ReactServerRendering = require("./ReactServerRendering");
+
+var assign = require("./Object.assign");
+var findDOMNode = require("./findDOMNode");
+var onlyChild = require("./onlyChild");
+
+ReactDefaultInjection.inject();
+
+var createElement = ReactElement.createElement;
+var createFactory = ReactElement.createFactory;
+var cloneElement = ReactElement.cloneElement;
+
+if ("production" !== process.env.NODE_ENV) {
+  createElement = ReactElementValidator.createElement;
+  createFactory = ReactElementValidator.createFactory;
+  cloneElement = ReactElementValidator.cloneElement;
+}
+
+var render = ReactPerf.measure('React', 'render', ReactMount.render);
+
+var React = {
+  Children: {
+    map: ReactChildren.map,
+    forEach: ReactChildren.forEach,
+    count: ReactChildren.count,
+    only: onlyChild
+  },
+  Component: ReactComponent,
+  DOM: ReactDOM,
+  PropTypes: ReactPropTypes,
+  initializeTouchEvents: function(shouldUseTouch) {
+    EventPluginUtils.useTouchEvents = shouldUseTouch;
+  },
+  createClass: ReactClass.createClass,
+  createElement: createElement,
+  cloneElement: cloneElement,
+  createFactory: createFactory,
+  createMixin: function(mixin) {
+    // Currently a noop. Will be used to validate and trace mixins.
+    return mixin;
+  },
+  constructAndRenderComponent: ReactMount.constructAndRenderComponent,
+  constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
+  findDOMNode: findDOMNode,
+  render: render,
+  renderToString: ReactServerRendering.renderToString,
+  renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
+  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
+  isValidElement: ReactElement.isValidElement,
+  withContext: ReactContext.withContext,
+
+  // Hook for JSX spread, don't use this for anything else.
+  __spread: assign
+};
+
+// Inject the runtime into a devtools global hook regardless of browser.
+// Allows for debugging when the hook is injected on the page.
+if (
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
+  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
+  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
+    CurrentOwner: ReactCurrentOwner,
+    InstanceHandles: ReactInstanceHandles,
+    Mount: ReactMount,
+    Reconciler: ReactReconciler,
+    TextComponent: ReactDOMTextComponent
+  });
+}
+
+if ("production" !== process.env.NODE_ENV) {
+  var ExecutionEnvironment = require("./ExecutionEnvironment");
+  if (ExecutionEnvironment.canUseDOM && window.top === window.self) {
+
+    // If we're in Chrome, look for the devtools marker and provide a download
+    // link if not installed.
+    if (navigator.userAgent.indexOf('Chrome') > -1) {
+      if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
+        console.debug(
+          'Download the React DevTools for a better development experience: ' +
+          'http://fb.me/react-devtools'
+        );
+      }
+    }
+
+    var expectedFeatures = [
+      // shims
+      Array.isArray,
+      Array.prototype.every,
+      Array.prototype.forEach,
+      Array.prototype.indexOf,
+      Array.prototype.map,
+      Date.now,
+      Function.prototype.bind,
+      Object.keys,
+      String.prototype.split,
+      String.prototype.trim,
+
+      // shams
+      Object.create,
+      Object.freeze
+    ];
+
+    for (var i = 0; i < expectedFeatures.length; i++) {
+      if (!expectedFeatures[i]) {
+        console.error(
+          'One or more ES5 shim/shams expected by React are not available: ' +
+          'http://fb.me/react-warning-polyfills'
+        );
+        break;
+      }
+    }
+  }
+}
+
+React.version = '0.13.1';
+
+module.exports = React;
+
+}).call(this,require('_process'))
+},{"./EventPluginUtils":19,"./ExecutionEnvironment":21,"./Object.assign":27,"./ReactChildren":33,"./ReactClass":34,"./ReactComponent":35,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactDOM":41,"./ReactDOMTextComponent":52,"./ReactDefaultInjection":55,"./ReactElement":58,"./ReactElementValidator":59,"./ReactInstanceHandles":67,"./ReactMount":71,"./ReactPerf":76,"./ReactPropTypes":79,"./ReactReconciler":82,"./ReactServerRendering":85,"./findDOMNode":118,"./onlyChild":145,"_process":15 [...]
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserComponentMixin
+ */
+
+'use strict';
+
+var findDOMNode = require("./findDOMNode");
+
+var ReactBrowserComponentMixin = {
+  /**
+   * Returns the DOM node rendered by this component.
+   *
+   * @return {DOMElement} The root node of this component.
+   * @final
+   * @protected
+   */
+  getDOMNode: function() {
+    return findDOMNode(this);
+  }
+};
+
+module.exports = ReactBrowserComponentMixin;
+
+},{"./findDOMNode":118}],31:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactBrowserEventEmitter
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPluginHub = require("./EventPluginHub");
+var EventPluginRegistry = require("./EventPluginRegistry");
+var ReactEventEmitterMixin = require("./ReactEventEmitterMixin");
+var ViewportMetrics = require("./ViewportMetrics");
+
+var assign = require("./Object.assign");
+var isEventSupported = require("./isEventSupported");
+
+/**
+ * Summary of `ReactBrowserEventEmitter` event handling:
+ *
+ *  - Top-level delegation is used to trap most native browser events. This
+ *    may only occur in the main thread and is the responsibility of
+ *    ReactEventListener, which is injected and can therefore support pluggable
+ *    event sources. This is the only work that occurs in the main thread.
+ *
+ *  - We normalize and de-duplicate events to account for browser quirks. This
+ *    may be done in the worker thread.
+ *
+ *  - Forward these native events (with the associated top-level type used to
+ *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
+ *    to extract any synthetic events.
+ *
+ *  - The `EventPluginHub` will then process each event by annotating them with
+ *    "dispatches", a sequence of listeners and IDs that care about that event.
+ *
+ *  - The `EventPluginHub` then dispatches the events.
+ *
+ * Overview of React and the event system:
+ *
+ * +------------+    .
+ * |    DOM     |    .
+ * +------------+    .
+ *       |           .
+ *       v           .
+ * +------------+    .
+ * | ReactEvent |    .
+ * |  Listener  |    .
+ * +------------+    .                         +-----------+
+ *       |           .               +--------+|SimpleEvent|
+ *       |           .               |         |Plugin     |
+ * +-----|------+    .               v         +-----------+
+ * |     |      |    .    +--------------+                    +------------+
+ * |     +-----------.--->|EventPluginHub|                    |    Event   |
+ * |            |    .    |              |     +-----------+  | Propagators|
+ * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
+ * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
+ * |            |    .    |              |     +-----------+  |  utilities |
+ * |     +-----------.--->|              |                    +------------+
+ * |     |      |    .    +--------------+
+ * +-----|------+    .                ^        +-----------+
+ *       |           .                |        |Enter/Leave|
+ *       +           .                +-------+|Plugin     |
+ * +-------------+   .                         +-----------+
+ * | application |   .
+ * |-------------|   .
+ * |             |   .
+ * |             |   .
+ * +-------------+   .
+ *                   .
+ *    React Core     .  General Purpose Event Plugin System
+ */
+
+var alreadyListeningTo = {};
+var isMonitoringScrollValue = false;
+var reactTopListenersCounter = 0;
+
+// For events like 'submit' which don't consistently bubble (which we trap at a
+// lower node than `document`), binding at `document` would cause duplicate
+// events so we don't include them here
+var topEventMapping = {
+  topBlur: 'blur',
+  topChange: 'change',
+  topClick: 'click',
+  topCompositionEnd: 'compositionend',
+  topCompositionStart: 'compositionstart',
+  topCompositionUpdate: 'compositionupdate',
+  topContextMenu: 'contextmenu',
+  topCopy: 'copy',
+  topCut: 'cut',
+  topDoubleClick: 'dblclick',
+  topDrag: 'drag',
+  topDragEnd: 'dragend',
+  topDragEnter: 'dragenter',
+  topDragExit: 'dragexit',
+  topDragLeave: 'dragleave',
+  topDragOver: 'dragover',
+  topDragStart: 'dragstart',
+  topDrop: 'drop',
+  topFocus: 'focus',
+  topInput: 'input',
+  topKeyDown: 'keydown',
+  topKeyPress: 'keypress',
+  topKeyUp: 'keyup',
+  topMouseDown: 'mousedown',
+  topMouseMove: 'mousemove',
+  topMouseOut: 'mouseout',
+  topMouseOver: 'mouseover',
+  topMouseUp: 'mouseup',
+  topPaste: 'paste',
+  topScroll: 'scroll',
+  topSelectionChange: 'selectionchange',
+  topTextInput: 'textInput',
+  topTouchCancel: 'touchcancel',
+  topTouchEnd: 'touchend',
+  topTouchMove: 'touchmove',
+  topTouchStart: 'touchstart',
+  topWheel: 'wheel'
+};
+
+/**
+ * To ensure no conflicts with other potential React instances on the page
+ */
+var topListenersIDKey = '_reactListenersID' + String(Math.random()).slice(2);
+
+function getListeningForDocument(mountAt) {
+  // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
+  // directly.
+  if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
+    mountAt[topListenersIDKey] = reactTopListenersCounter++;
+    alreadyListeningTo[mountAt[topListenersIDKey]] = {};
+  }
+  return alreadyListeningTo[mountAt[topListenersIDKey]];
+}
+
+/**
+ * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
+ * example:
+ *
+ *   ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
+ *
+ * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
+ *
+ * @internal
+ */
+var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {
+
+  /**
+   * Injectable event backend
+   */
+  ReactEventListener: null,
+
+  injection: {
+    /**
+     * @param {object} ReactEventListener
+     */
+    injectReactEventListener: function(ReactEventListener) {
+      ReactEventListener.setHandleTopLevel(
+        ReactBrowserEventEmitter.handleTopLevel
+      );
+      ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
+    }
+  },
+
+  /**
+   * Sets whether or not any created callbacks should be enabled.
+   *
+   * @param {boolean} enabled True if callbacks should be enabled.
+   */
+  setEnabled: function(enabled) {
+    if (ReactBrowserEventEmitter.ReactEventListener) {
+      ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
+    }
+  },
+
+  /**
+   * @return {boolean} True if callbacks are enabled.
+   */
+  isEnabled: function() {
+    return !!(
+      (ReactBrowserEventEmitter.ReactEventListener && ReactBrowserEventEmitter.ReactEventListener.isEnabled())
+    );
+  },
+
+  /**
+   * We listen for bubbled touch events on the document object.
+   *
+   * Firefox v8.01 (and possibly others) exhibited strange behavior when
+   * mounting `onmousemove` events at some node that was not the document
+   * element. The symptoms were that if your mouse is not moving over something
+   * contained within that mount point (for example on the background) the
+   * top-level listeners for `onmousemove` won't be called. However, if you
+   * register the `mousemove` on the document object, then it will of course
+   * catch all `mousemove`s. This along with iOS quirks, justifies restricting
+   * top-level listeners to the document object only, at least for these
+   * movement types of events and possibly all events.
+   *
+   * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
+   *
+   * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
+   * they bubble to document.
+   *
+   * @param {string} registrationName Name of listener (e.g. `onClick`).
+   * @param {object} contentDocumentHandle Document which owns the container
+   */
+  listenTo: function(registrationName, contentDocumentHandle) {
+    var mountAt = contentDocumentHandle;
+    var isListening = getListeningForDocument(mountAt);
+    var dependencies = EventPluginRegistry.
+      registrationNameDependencies[registrationName];
+
+    var topLevelTypes = EventConstants.topLevelTypes;
+    for (var i = 0, l = dependencies.length; i < l; i++) {
+      var dependency = dependencies[i];
+      if (!(
+            (isListening.hasOwnProperty(dependency) && isListening[dependency])
+          )) {
+        if (dependency === topLevelTypes.topWheel) {
+          if (isEventSupported('wheel')) {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'wheel',
+              mountAt
+            );
+          } else if (isEventSupported('mousewheel')) {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'mousewheel',
+              mountAt
+            );
+          } else {
+            // Firefox needs to capture a different mouse scroll event.
+            // @see http://www.quirksmode.org/dom/events/tests/scroll.html
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topWheel,
+              'DOMMouseScroll',
+              mountAt
+            );
+          }
+        } else if (dependency === topLevelTypes.topScroll) {
+
+          if (isEventSupported('scroll', true)) {
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topScroll,
+              'scroll',
+              mountAt
+            );
+          } else {
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topScroll,
+              'scroll',
+              ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
+            );
+          }
+        } else if (dependency === topLevelTypes.topFocus ||
+            dependency === topLevelTypes.topBlur) {
+
+          if (isEventSupported('focus', true)) {
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topFocus,
+              'focus',
+              mountAt
+            );
+            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+              topLevelTypes.topBlur,
+              'blur',
+              mountAt
+            );
+          } else if (isEventSupported('focusin')) {
+            // IE has `focusin` and `focusout` events which bubble.
+            // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topFocus,
+              'focusin',
+              mountAt
+            );
+            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+              topLevelTypes.topBlur,
+              'focusout',
+              mountAt
+            );
+          }
+
+          // to make sure blur and focus event listeners are only attached once
+          isListening[topLevelTypes.topBlur] = true;
+          isListening[topLevelTypes.topFocus] = true;
+        } else if (topEventMapping.hasOwnProperty(dependency)) {
+          ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+            dependency,
+            topEventMapping[dependency],
+            mountAt
+          );
+        }
+
+        isListening[dependency] = true;
+      }
+    }
+  },
+
+  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+    return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
+      topLevelType,
+      handlerBaseName,
+      handle
+    );
+  },
+
+  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+    return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
+      topLevelType,
+      handlerBaseName,
+      handle
+    );
+  },
+
+  /**
+   * Listens to window scroll and resize events. We cache scroll values so that
+   * application code can access them without triggering reflows.
+   *
+   * NOTE: Scroll events do not bubble.
+   *
+   * @see http://www.quirksmode.org/dom/events/scroll.html
+   */
+  ensureScrollValueMonitoring: function() {
+    if (!isMonitoringScrollValue) {
+      var refresh = ViewportMetrics.refreshScrollValues;
+      ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
+      isMonitoringScrollValue = true;
+    }
+  },
+
+  eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,
+
+  registrationNameModules: EventPluginHub.registrationNameModules,
+
+  putListener: EventPluginHub.putListener,
+
+  getListener: EventPluginHub.getListener,
+
+  deleteListener: EventPluginHub.deleteListener,
+
+  deleteAllListeners: EventPluginHub.deleteAllListeners
+
+});
+
+module.exports = ReactBrowserEventEmitter;
+
+},{"./EventConstants":15,"./EventPluginHub":17,"./EventPluginRegistry":18,"./Object.assign":27,"./ReactEventEmitterMixin":62,"./ViewportMetrics":105,"./isEventSupported":137}],32:[function(require,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildReconciler
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactReconciler = require("./ReactReconciler");
+
+var flattenChildren = require("./flattenChildren");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+
+/**
+ * ReactChildReconciler provides helpers for initializing or updating a set of
+ * children. Its output is suitable for passing it onto ReactMultiChild which
+ * does diffed reordering and insertion.
+ */
+var ReactChildReconciler = {
+
+  /**
+   * Generates a "mount image" for each of the supplied children. In the case
+   * of `ReactDOMComponent`, a mount image is a string of markup.
+   *
+   * @param {?object} nestedChildNodes Nested child maps.
+   * @return {?object} A set of child instances.
+   * @internal
+   */
+  instantiateChildren: function(nestedChildNodes, transaction, context) {
+    var children = flattenChildren(nestedChildNodes);
+    for (var name in children) {
+      if (children.hasOwnProperty(name)) {
+        var child = children[name];
+        // The rendered children must be turned into instances as they're
+        // mounted.
+        var childInstance = instantiateReactComponent(child, null);
+        children[name] = childInstance;
+      }
+    }
+    return children;
+  },
+
+  /**
+   * Updates the rendered children and returns a new set of children.
+   *
+   * @param {?object} prevChildren Previously initialized set of children.
+   * @param {?object} nextNestedChildNodes Nested child maps.
+   * @param {ReactReconcileTransaction} transaction
+   * @param {object} context
+   * @return {?object} A new set of child instances.
+   * @internal
+   */
+  updateChildren: function(
+    prevChildren,
+    nextNestedChildNodes,
+    transaction,
+    context) {
+    // We currently don't have a way to track moves here but if we use iterators
+    // instead of for..in we can zip the iterators and check if an item has
+    // moved.
+    // TODO: If nothing has changed, return the prevChildren object so that we
+    // can quickly bailout if nothing has changed.
+    var nextChildren = flattenChildren(nextNestedChildNodes);
+    if (!nextChildren && !prevChildren) {
+      return null;
+    }
+    var name;
+    for (name in nextChildren) {
+      if (!nextChildren.hasOwnProperty(name)) {
+        continue;
+      }
+      var prevChild = prevChildren && prevChildren[name];
+      var prevElement = prevChild && prevChild._currentElement;
+      var nextElement = nextChildren[name];
+      if (shouldUpdateReactComponent(prevElement, nextElement)) {
+        ReactReconciler.receiveComponent(
+          prevChild, nextElement, transaction, context
+        );
+        nextChildren[name] = prevChild;
+      } else {
+        if (prevChild) {
+          ReactReconciler.unmountComponent(prevChild, name);
+        }
+        // The child must be instantiated before it's mounted.
+        var nextChildInstance = instantiateReactComponent(
+          nextElement,
+          null
+        );
+        nextChildren[name] = nextChildInstance;
+      }
+    }
+    // Unmount children that are no longer present.
+    for (name in prevChildren) {
+      if (prevChildren.hasOwnProperty(name) &&
+          !(nextChildren && nextChildren.hasOwnProperty(name))) {
+        ReactReconciler.unmountComponent(prevChildren[name]);
+      }
+    }
+    return nextChildren;
+  },
+
+  /**
+   * Unmounts all rendered children. This should be used to clean up children
+   * when this component is unmounted.
+   *
+   * @param {?object} renderedChildren Previously initialized set of children.
+   * @internal
+   */
+  unmountChildren: function(renderedChildren) {
+    for (var name in renderedChildren) {
+      var renderedChild = renderedChildren[name];
+      ReactReconciler.unmountComponent(renderedChild);
+    }
+  }
+
+};
+
+module.exports = ReactChildReconciler;
+
+},{"./ReactReconciler":82,"./flattenChildren":119,"./instantiateReactComponent":135,"./shouldUpdateReactComponent":152}],33:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildren
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+var ReactFragment = require("./ReactFragment");
+
+var traverseAllChildren = require("./traverseAllChildren");
+var warning = require("./warning");
+
+var twoArgumentPooler = PooledClass.twoArgumentPooler;
+var threeArgumentPooler = PooledClass.threeArgumentPooler;
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * traversal. Allows avoiding binding callbacks.
+ *
+ * @constructor ForEachBookKeeping
+ * @param {!function} forEachFunction Function to perform traversal with.
+ * @param {?*} forEachContext Context to perform context with.
+ */
+function ForEachBookKeeping(forEachFunction, forEachContext) {
+  this.forEachFunction = forEachFunction;
+  this.forEachContext = forEachContext;
+}
+PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
+
+function forEachSingleChild(traverseContext, child, name, i) {
+  var forEachBookKeeping = traverseContext;
+  forEachBookKeeping.forEachFunction.call(
+    forEachBookKeeping.forEachContext, child, i);
+}
+
+/**
+ * Iterates through children that are typically specified as `props.children`.
+ *
+ * The provided forEachFunc(child, index) will be called for each
+ * leaf child.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} forEachFunc.
+ * @param {*} forEachContext Context for forEachContext.
+ */
+function forEachChildren(children, forEachFunc, forEachContext) {
+  if (children == null) {
+    return children;
+  }
+
+  var traverseContext =
+    ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
+  traverseAllChildren(children, forEachSingleChild, traverseContext);
+  ForEachBookKeeping.release(traverseContext);
+}
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * mapping. Allows avoiding binding callbacks.
+ *
+ * @constructor MapBookKeeping
+ * @param {!*} mapResult Object containing the ordered map of results.
+ * @param {!function} mapFunction Function to perform mapping with.
+ * @param {?*} mapContext Context to perform mapping with.
+ */
+function MapBookKeeping(mapResult, mapFunction, mapContext) {
+  this.mapResult = mapResult;
+  this.mapFunction = mapFunction;
+  this.mapContext = mapContext;
+}
+PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);
+
+function mapSingleChildIntoContext(traverseContext, child, name, i) {
+  var mapBookKeeping = traverseContext;
+  var mapResult = mapBookKeeping.mapResult;
+
+  var keyUnique = !mapResult.hasOwnProperty(name);
+  if ("production" !== process.env.NODE_ENV) {
+    ("production" !== process.env.NODE_ENV ? warning(
+      keyUnique,
+      'ReactChildren.map(...): Encountered two children with the same key, ' +
+      '`%s`. Child keys must be unique; when two children share a key, only ' +
+      'the first child will be used.',
+      name
+    ) : null);
+  }
+
+  if (keyUnique) {
+    var mappedChild =
+      mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
+    mapResult[name] = mappedChild;
+  }
+}
+
+/**
+ * Maps children that are typically specified as `props.children`.
+ *
+ * The provided mapFunction(child, key, index) will be called for each
+ * leaf child.
+ *
+ * TODO: This may likely break any calls to `ReactChildren.map` that were
+ * previously relying on the fact that we guarded against null children.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} mapFunction.
+ * @param {*} mapContext Context for mapFunction.
+ * @return {object} Object containing the ordered map of results.
+ */
+function mapChildren(children, func, context) {
+  if (children == null) {
+    return children;
+  }
+
+  var mapResult = {};
+  var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
+  traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
+  MapBookKeeping.release(traverseContext);
+  return ReactFragment.create(mapResult);
+}
+
+function forEachSingleChildDummy(traverseContext, child, name, i) {
+  return null;
+}
+
+/**
+ * Count the number of children that are typically specified as
+ * `props.children`.
+ *
+ * @param {?*} children Children tree container.
+ * @return {number} The number of children.
+ */
+function countChildren(children, context) {
+  return traverseAllChildren(children, forEachSingleChildDummy, null);
+}
+
+var ReactChildren = {
+  forEach: forEachChildren,
+  map: mapChildren,
+  count: countChildren
+};
+
+module.exports = ReactChildren;
+
+}).call(this,require('_process'))
+},{"./PooledClass":28,"./ReactFragment":64,"./traverseAllChildren":154,"./warning":155,"_process":157}],34:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactClass
+ */
+
+'use strict';
+
+var ReactComponent = require("./ReactComponent");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactErrorUtils = require("./ReactErrorUtils");
+var ReactInstanceMap = require("./ReactInstanceMap");
+var ReactLifeCycle = require("./ReactLifeCycle");
+var ReactPropTypeLocations = require("./ReactPropTypeLocations");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+var ReactUpdateQueue = require("./ReactUpdateQueue");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var keyMirror = require("./keyMirror");
+var keyOf = require("./keyOf");
+var warning = require("./warning");
+
+var MIXINS_KEY = keyOf({mixins: null});
+
+/**
+ * Policies that describe methods in `ReactClassInterface`.
+ */
+var SpecPolicy = keyMirror({
+  /**
+   * These methods may be defined only once by the class specification or mixin.
+   */
+  DEFINE_ONCE: null,
+  /**
+   * These methods may be defined by both the class specification and mixins.
+   * Subsequent definitions will be chained. These methods must return void.
+   */
+  DEFINE_MANY: null,
+  /**
+   * These methods are overriding the base class.
+   */
+  OVERRIDE_BASE: null,
+  /**
+   * These methods are similar to DEFINE_MANY, except we assume they return
+   * objects. We try to merge the keys of the return values of all the mixed in
+   * functions. If there is a key conflict we throw.
+   */
+  DEFINE_MANY_MERGED: null
+});
+
+
+var injectedMixins = [];
+
+/**
+ * Composite components are higher-level components that compose other composite
+ * or native components.
+ *
+ * To create a new type of `ReactClass`, pass a specification of
+ * your new class to `React.createClass`. The only requirement of your class
+ * specification is that you implement a `render` method.
+ *
+ *   var MyComponent = React.createClass({
+ *     render: function() {
+ *       return <div>Hello World</div>;
+ *     }
+ *   });
+ *
+ * The class specification supports a specific protocol of methods that have
+ * special meaning (e.g. `render`). See `ReactClassInterface` for
+ * more the comprehensive protocol. Any other properties and methods in the
+ * class specification will available on the prototype.
+ *
+ * @interface ReactClassInterface
+ * @internal
+ */
+var ReactClassInterface = {
+
+  /**
+   * An array of Mixin objects to include when defining your component.
+   *
+   * @type {array}
+   * @optional
+   */
+  mixins: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * An object containing properties and methods that should be defined on
+   * the component's constructor instead of its prototype (static methods).
+   *
+   * @type {object}
+   * @optional
+   */
+  statics: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of prop types for this component.
+   *
+   * @type {object}
+   * @optional
+   */
+  propTypes: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of context types for this component.
+   *
+   * @type {object}
+   * @optional
+   */
+  contextTypes: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Definition of context types this component sets for its children.
+   *
+   * @type {object}
+   * @optional
+   */
+  childContextTypes: SpecPolicy.DEFINE_MANY,
+
+  // ==== Definition methods ====
+
+  /**
+   * Invoked when the component is mounted. Values in the mapping will be set on
+   * `this.props` if that prop is not specified (i.e. using an `in` check).
+   *
+   * This method is invoked before `getInitialState` and therefore cannot rely
+   * on `this.state` or use `this.setState`.
+   *
+   * @return {object}
+   * @optional
+   */
+  getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * Invoked once before the component is mounted. The return value will be used
+   * as the initial value of `this.state`.
+   *
+   *   getInitialState: function() {
+   *     return {
+   *       isOn: false,
+   *       fooBaz: new BazFoo()
+   *     }
+   *   }
+   *
+   * @return {object}
+   * @optional
+   */
+  getInitialState: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * @return {object}
+   * @optional
+   */
+  getChildContext: SpecPolicy.DEFINE_MANY_MERGED,
+
+  /**
+   * Uses props from `this.props` and state from `this.state` to render the
+   * structure of the component.
+   *
+   * No guarantees are made about when or how often this method is invoked, so
+   * it must not have side effects.
+   *
+   *   render: function() {
+   *     var name = this.props.name;
+   *     return <div>Hello, {name}!</div>;
+   *   }
+   *
+   * @return {ReactComponent}
+   * @nosideeffects
+   * @required
+   */
+  render: SpecPolicy.DEFINE_ONCE,
+
+
+
+  // ==== Delegate methods ====
+
+  /**
+   * Invoked when the component is initially created and about to be mounted.
+   * This may have side effects, but any external subscriptions or data created
+   * by this method must be cleaned up in `componentWillUnmount`.
+   *
+   * @optional
+   */
+  componentWillMount: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component has been mounted and has a DOM representation.
+   * However, there is no guarantee that the DOM node is in the document.
+   *
+   * Use this as an opportunity to operate on the DOM when the component has
+   * been mounted (initialized and rendered) for the first time.
+   *
+   * @param {DOMElement} rootNode DOM element representing the component.
+   * @optional
+   */
+  componentDidMount: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked before the component receives new props.
+   *
+   * Use this as an opportunity to react to a prop transition by updating the
+   * state using `this.setState`. Current props are accessed via `this.props`.
+   *
+   *   componentWillReceiveProps: function(nextProps, nextContext) {
+   *     this.setState({
+   *       likesIncreasing: nextProps.likeCount > this.props.likeCount
+   *     });
+   *   }
+   *
+   * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
+   * transition may cause a state change, but the opposite is not true. If you
+   * need it, you are probably looking for `componentWillUpdate`.
+   *
+   * @param {object} nextProps
+   * @optional
+   */
+  componentWillReceiveProps: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked while deciding if the component should be updated as a result of
+   * receiving new props, state and/or context.
+   *
+   * Use this as an opportunity to `return false` when you're certain that the
+   * transition to the new props/state/context will not require a component
+   * update.
+   *
+   *   shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+   *     return !equal(nextProps, this.props) ||
+   *       !equal(nextState, this.state) ||
+   *       !equal(nextContext, this.context);
+   *   }
+   *
+   * @param {object} nextProps
+   * @param {?object} nextState
+   * @param {?object} nextContext
+   * @return {boolean} True if the component should update.
+   * @optional
+   */
+  shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,
+
+  /**
+   * Invoked when the component is about to update due to a transition from
+   * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
+   * and `nextContext`.
+   *
+   * Use this as an opportunity to perform preparation before an update occurs.
+   *
+   * NOTE: You **cannot** use `this.setState()` in this method.
+   *
+   * @param {object} nextProps
+   * @param {?object} nextState
+   * @param {?object} nextContext
+   * @param {ReactReconcileTransaction} transaction
+   * @optional
+   */
+  componentWillUpdate: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component's DOM representation has been updated.
+   *
+   * Use this as an opportunity to operate on the DOM when the component has
+   * been updated.
+   *
+   * @param {object} prevProps
+   * @param {?object} prevState
+   * @param {?object} prevContext
+   * @param {DOMElement} rootNode DOM element representing the component.
+   * @optional
+   */
+  componentDidUpdate: SpecPolicy.DEFINE_MANY,
+
+  /**
+   * Invoked when the component is about to be removed from its parent and have
+   * its DOM representation destroyed.
+   *
+   * Use this as an opportunity to deallocate any external resources.
+   *
+   * NOTE: There is no `componentDidUnmount` since your component will have been
+   * destroyed by that point.
+   *
+   * @optional
+   */
+  componentWillUnmount: SpecPolicy.DEFINE_MANY,
+
+
+
+  // ==== Advanced methods ====
+
+  /**
+   * Updates the component's currently mounted DOM representation.
+   *
+   * By default, this implements React's rendering and reconciliation algorithm.
+   * Sophisticated clients may wish to override this.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   * @overridable
+   */
+  updateComponent: SpecPolicy.OVERRIDE_BASE
+
+};
+
+/**
+ * Mapping from class specification keys to special processing functions.
+ *
+ * Although these are declared like instance properties in the specification
+ * when defining classes using `React.createClass`, they are actually static
+ * and are accessible on the constructor instead of the prototype. Despite
+ * being static, they must be defined outside of the "statics" key under
+ * which all other static methods are defined.
+ */
+var RESERVED_SPEC_KEYS = {
+  displayName: function(Constructor, displayName) {
+    Constructor.displayName = displayName;
+  },
+  mixins: function(Constructor, mixins) {
+    if (mixins) {
+      for (var i = 0; i < mixins.length; i++) {
+        mixSpecIntoComponent(Constructor, mixins[i]);
+      }
+    }
+  },
+  childContextTypes: function(Constructor, childContextTypes) {
+    if ("production" !== process.env.NODE_ENV) {
+      validateTypeDef(
+        Constructor,
+        childContextTypes,
+        ReactPropTypeLocations.childContext
+      );
+    }
+    Constructor.childContextTypes = assign(
+      {},
+      Constructor.childContextTypes,
+      childContextTypes
+    );
+  },
+  contextTypes: function(Constructor, contextTypes) {
+    if ("production" !== process.env.NODE_ENV) {
+      validateTypeDef(
+        Constructor,
+        contextTypes,
+        ReactPropTypeLocations.context
+      );
+    }
+    Constructor.contextTypes = assign(
+      {},
+      Constructor.contextTypes,
+      contextTypes
+    );
+  },
+  /**
+   * Special case getDefaultProps which should move into statics but requires
+   * automatic merging.
+   */
+  getDefaultProps: function(Constructor, getDefaultProps) {
+    if (Constructor.getDefaultProps) {
+      Constructor.getDefaultProps = createMergedResultFunction(
+        Constructor.getDefaultProps,
+        getDefaultProps
+      );
+    } else {
+      Constructor.getDefaultProps = getDefaultProps;
+    }
+  },
+  propTypes: function(Constructor, propTypes) {
+    if ("production" !== process.env.NODE_ENV) {
+      validateTypeDef(
+        Constructor,
+        propTypes,
+        ReactPropTypeLocations.prop
+      );
+    }
+    Constructor.propTypes = assign(
+      {},
+      Constructor.propTypes,
+      propTypes
+    );
+  },
+  statics: function(Constructor, statics) {
+    mixStaticSpecIntoComponent(Constructor, statics);
+  }
+};
+
+function validateTypeDef(Constructor, typeDef, location) {
+  for (var propName in typeDef) {
+    if (typeDef.hasOwnProperty(propName)) {
+      // use a warning instead of an invariant so components
+      // don't show up in prod but not in __DEV__
+      ("production" !== process.env.NODE_ENV ? warning(
+        typeof typeDef[propName] === 'function',
+        '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+        'React.PropTypes.',
+        Constructor.displayName || 'ReactClass',
+        ReactPropTypeLocationNames[location],
+        propName
+      ) : null);
+    }
+  }
+}
+
+function validateMethodOverride(proto, name) {
+  var specPolicy = ReactClassInterface.hasOwnProperty(name) ?
+    ReactClassInterface[name] :
+    null;
+
+  // Disallow overriding of base class methods unless explicitly allowed.
+  if (ReactClassMixin.hasOwnProperty(name)) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      specPolicy === SpecPolicy.OVERRIDE_BASE,
+      'ReactClassInterface: You are attempting to override ' +
+      '`%s` from your class specification. Ensure that your method names ' +
+      'do not overlap with React methods.',
+      name
+    ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
+  }
+
+  // Disallow defining methods more than once unless explicitly allowed.
+  if (proto.hasOwnProperty(name)) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      specPolicy === SpecPolicy.DEFINE_MANY ||
+      specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
+      'ReactClassInterface: You are attempting to define ' +
+      '`%s` on your component more than once. This conflict may be due ' +
+      'to a mixin.',
+      name
+    ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
+    specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
+  }
+}
+
+/**
+ * Mixin helper which handles policy validation and reserved
+ * specification keys when building React classses.
+ */
+function mixSpecIntoComponent(Constructor, spec) {
+  if (!spec) {
+    return;
+  }
+
+  ("production" !== process.env.NODE_ENV ? invariant(
+    typeof spec !== 'function',
+    'ReactClass: You\'re attempting to ' +
+    'use a component class as a mixin. Instead, just use a regular object.'
+  ) : invariant(typeof spec !== 'function'));
+  ("production" !== process.env.NODE_ENV ? invariant(
+    !ReactElement.isValidElement(spec),
+    'ReactClass: You\'re attempting to ' +
+    'use a component as a mixin. Instead, just use a regular object.'
+  ) : invariant(!ReactElement.isValidElement(spec)));
+
+  var proto = Constructor.prototype;
+
+  // By handling mixins before any other properties, we ensure the same
+  // chaining order is applied to methods with DEFINE_MANY policy, whether
+  // mixins are listed before or after these methods in the spec.
+  if (spec.hasOwnProperty(MIXINS_KEY)) {
+    RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
+  }
+
+  for (var name in spec) {
+    if (!spec.hasOwnProperty(name)) {
+      continue;
+    }
+
+    if (name === MIXINS_KEY) {
+      // We have already handled mixins in a special case above
+      continue;
+    }
+
+    var property = spec[name];
+    validateMethodOverride(proto, name);
+
+    if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
+      RESERVED_SPEC_KEYS[name](Constructor, property);
+    } else {
+      // Setup methods on prototype:
+      // The following member methods should not be automatically bound:
+      // 1. Expected ReactClass methods (in the "interface").
+      // 2. Overridden methods (that were mixed in).
+      var isReactClassMethod =
+        ReactClassInterface.hasOwnProperty(name);
+      var isAlreadyDefined = proto.hasOwnProperty(name);
+      var markedDontBind = property && property.__reactDontBind;
+      var isFunction = typeof property === 'function';
+      var shouldAutoBind =
+        isFunction &&
+        !isReactClassMethod &&
+        !isAlreadyDefined &&
+        !markedDontBind;
+
+      if (shouldAutoBind) {
+        if (!proto.__reactAutoBindMap) {
+          proto.__reactAutoBindMap = {};
+        }
+        proto.__reactAutoBindMap[name] = property;
+        proto[name] = property;
+      } else {
+        if (isAlreadyDefined) {
+          var specPolicy = ReactClassInterface[name];
+
+          // These cases should already be caught by validateMethodOverride
+          ("production" !== process.env.NODE_ENV ? invariant(
+            isReactClassMethod && (
+              (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)
+            ),
+            'ReactClass: Unexpected spec policy %s for key %s ' +
+            'when mixing in component specs.',
+            specPolicy,
+            name
+          ) : invariant(isReactClassMethod && (
+            (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY)
+          )));
+
+          // For methods which are defined more than once, call the existing
+          // methods before calling the new property, merging if appropriate.
+          if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
+            proto[name] = createMergedResultFunction(proto[name], property);
+          } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
+            proto[name] = createChainedFunction(proto[name], property);
+          }
+        } else {
+          proto[name] = property;
+          if ("production" !== process.env.NODE_ENV) {
+            // Add verbose displayName to the function, which helps when looking
+            // at profiling tools.
+            if (typeof property === 'function' && spec.displayName) {
+              proto[name].displayName = spec.displayName + '_' + name;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+function mixStaticSpecIntoComponent(Constructor, statics) {
+  if (!statics) {
+    return;
+  }
+  for (var name in statics) {
+    var property = statics[name];
+    if (!statics.hasOwnProperty(name)) {
+      continue;
+    }
+
+    var isReserved = name in RESERVED_SPEC_KEYS;
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !isReserved,
+      'ReactClass: You are attempting to define a reserved ' +
+      'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
+      'as an instance property instead; it will still be accessible on the ' +
+      'constructor.',
+      name
+    ) : invariant(!isReserved));
+
+    var isInherited = name in Constructor;
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !isInherited,
+      'ReactClass: You are attempting to define ' +
+      '`%s` on your component more than once. This conflict may be ' +
+      'due to a mixin.',
+      name
+    ) : invariant(!isInherited));
+    Constructor[name] = property;
+  }
+}
+
+/**
+ * Merge two objects, but throw if both contain the same key.
+ *
+ * @param {object} one The first object, which is mutated.
+ * @param {object} two The second object
+ * @return {object} one after it has been mutated to contain everything in two.
+ */
+function mergeIntoWithNoDuplicateKeys(one, two) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    one && two && typeof one === 'object' && typeof two === 'object',
+    'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.'
+  ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));
+
+  for (var key in two) {
+    if (two.hasOwnProperty(key)) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        one[key] === undefined,
+        'mergeIntoWithNoDuplicateKeys(): ' +
+        'Tried to merge two objects with the same key: `%s`. This conflict ' +
+        'may be due to a mixin; in particular, this may be caused by two ' +
+        'getInitialState() or getDefaultProps() methods returning objects ' +
+        'with clashing keys.',
+        key
+      ) : invariant(one[key] === undefined));
+      one[key] = two[key];
+    }
+  }
+  return one;
+}
+
+/**
+ * Creates a function that invokes two functions and merges their return values.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createMergedResultFunction(one, two) {
+  return function mergedResult() {
+    var a = one.apply(this, arguments);
+    var b = two.apply(this, arguments);
+    if (a == null) {
+      return b;
+    } else if (b == null) {
+      return a;
+    }
+    var c = {};
+    mergeIntoWithNoDuplicateKeys(c, a);
+    mergeIntoWithNoDuplicateKeys(c, b);
+    return c;
+  };
+}
+
+/**
+ * Creates a function that invokes two functions and ignores their return vales.
+ *
+ * @param {function} one Function to invoke first.
+ * @param {function} two Function to invoke second.
+ * @return {function} Function that invokes the two argument functions.
+ * @private
+ */
+function createChainedFunction(one, two) {
+  return function chainedFunction() {
+    one.apply(this, arguments);
+    two.apply(this, arguments);
+  };
+}
+
+/**
+ * Binds a method to the component.
+ *
+ * @param {object} component Component whose method is going to be bound.
+ * @param {function} method Method to be bound.
+ * @return {function} The bound method.
+ */
+function bindAutoBindMethod(component, method) {
+  var boundMethod = method.bind(component);
+  if ("production" !== process.env.NODE_ENV) {
+    boundMethod.__reactBoundContext = component;
+    boundMethod.__reactBoundMethod = method;
+    boundMethod.__reactBoundArguments = null;
+    var componentName = component.constructor.displayName;
+    var _bind = boundMethod.bind;
+    /* eslint-disable block-scoped-var, no-undef */
+    boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+      // User is trying to bind() an autobound method; we effectively will
+      // ignore the value of "this" that the user is trying to use, so
+      // let's warn.
+      if (newThis !== component && newThis !== null) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          false,
+          'bind(): React component methods may only be bound to the ' +
+          'component instance. See %s',
+          componentName
+        ) : null);
+      } else if (!args.length) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          false,
+          'bind(): You are binding a component method to the component. ' +
+          'React does this for you automatically in a high-performance ' +
+          'way, so you can safely remove this call. See %s',
+          componentName
+        ) : null);
+        return boundMethod;
+      }
+      var reboundMethod = _bind.apply(boundMethod, arguments);
+      reboundMethod.__reactBoundContext = component;
+      reboundMethod.__reactBoundMethod = method;
+      reboundMethod.__reactBoundArguments = args;
+      return reboundMethod;
+      /* eslint-enable */
+    };
+  }
+  return boundMethod;
+}
+
+/**
+ * Binds all auto-bound methods in a component.
+ *
+ * @param {object} component Component whose method is going to be bound.
+ */
+function bindAutoBindMethods(component) {
+  for (var autoBindKey in component.__reactAutoBindMap) {
+    if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
+      var method = component.__reactAutoBindMap[autoBindKey];
+      component[autoBindKey] = bindAutoBindMethod(
+        component,
+        ReactErrorUtils.guard(
+          method,
+          component.constructor.displayName + '.' + autoBindKey
+        )
+      );
+    }
+  }
+}
+
+var typeDeprecationDescriptor = {
+  enumerable: false,
+  get: function() {
+    var displayName = this.displayName || this.name || 'Component';
+    ("production" !== process.env.NODE_ENV ? warning(
+      false,
+      '%s.type is deprecated. Use %s directly to access the class.',
+      displayName,
+      displayName
+    ) : null);
+    Object.defineProperty(this, 'type', {
+      value: this
+    });
+    return this;
+  }
+};
+
+/**
+ * Add more to the ReactClass base class. These are all legacy features and
+ * therefore not already part of the modern ReactComponent.
+ */
+var ReactClassMixin = {
+
+  /**
+   * TODO: This will be deprecated because state should always keep a consistent
+   * type signature and the only use case for this, is to avoid that.
+   */
+  replaceState: function(newState, callback) {
+    ReactUpdateQueue.enqueueReplaceState(this, newState);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  },
+
+  /**
+   * Checks whether or not this composite component is mounted.
+   * @return {boolean} True if mounted, false otherwise.
+   * @protected
+   * @final
+   */
+  isMounted: function() {
+    if ("production" !== process.env.NODE_ENV) {
+      var owner = ReactCurrentOwner.current;
+      if (owner !== null) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          owner._warnedAboutRefsInRender,
+          '%s is accessing isMounted inside its render() function. ' +
+          'render() should be a pure function of props and state. It should ' +
+          'never access something that requires stale data from the previous ' +
+          'render, such as refs. Move this logic to componentDidMount and ' +
+          'componentDidUpdate instead.',
+          owner.getName() || 'A component'
+        ) : null);
+        owner._warnedAboutRefsInRender = true;
+      }
+    }
+    var internalInstance = ReactInstanceMap.get(this);
+    return (
+      internalInstance &&
+      internalInstance !== ReactLifeCycle.currentlyMountingInstance
+    );
+  },
+
+  /**
+   * Sets a subset of the props.
+   *
+   * @param {object} partialProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @public
+   * @deprecated
+   */
+  setProps: function(partialProps, callback) {
+    ReactUpdateQueue.enqueueSetProps(this, partialProps);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  },
+
+  /**
+   * Replace all the props.
+   *
+   * @param {object} newProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @public
+   * @deprecated
+   */
+  replaceProps: function(newProps, callback) {
+    ReactUpdateQueue.enqueueReplaceProps(this, newProps);
+    if (callback) {
+      ReactUpdateQueue.enqueueCallback(this, callback);
+    }
+  }
+};
+
+var ReactClassComponent = function() {};
+assign(
+  ReactClassComponent.prototype,
+  ReactComponent.prototype,
+  ReactClassMixin
+);
+
+/**
+ * Module for creating composite components.
+ *
+ * @class ReactClass
+ */
+var ReactClass = {
+
+  /**
+   * Creates a composite component class given a class specification.
+   *
+   * @param {object} spec Class specification (which must define `render`).
+   * @return {function} Component constructor function.
+   * @public
+   */
+  createClass: function(spec) {
+    var Constructor = function(props, context) {
+      // This constructor is overridden by mocks. The argument is used
+      // by mocks to assert on what gets mounted.
+
+      if ("production" !== process.env.NODE_ENV) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          this instanceof Constructor,
+          'Something is calling a React component directly. Use a factory or ' +
+          'JSX instead. See: http://fb.me/react-legacyfactory'
+        ) : null);
+      }
+
+      // Wire up auto-binding
+      if (this.__reactAutoBindMap) {
+        bindAutoBindMethods(this);
+      }
+
+      this.props = props;
+      this.context = context;
+      this.state = null;
+
+      // ReactClasses doesn't have constructors. Instead, they use the
+      // getInitialState and componentWillMount methods for initialization.
+
+      var initialState = this.getInitialState ? this.getInitialState() : null;
+      if ("production" !== process.env.NODE_ENV) {
+        // We allow auto-mocks to proceed as if they're returning null.
+        if (typeof initialState === 'undefined' &&
+            this.getInitialState._isMockFunction) {
+          // This is probably bad practice. Consider warning here and
+          // deprecating this convenience.
+          initialState = null;
+        }
+      }
+      ("production" !== process.env.NODE_ENV ? invariant(
+        typeof initialState === 'object' && !Array.isArray(initialState),
+        '%s.getInitialState(): must return an object or null',
+        Constructor.displayName || 'ReactCompositeComponent'
+      ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
+
+      this.state = initialState;
+    };
+    Constructor.prototype = new ReactClassComponent();
+    Constructor.prototype.constructor = Constructor;
+
+    injectedMixins.forEach(
+      mixSpecIntoComponent.bind(null, Constructor)
+    );
+
+    mixSpecIntoComponent(Constructor, spec);
+
+    // Initialize the defaultProps property after all mixins have been merged
+    if (Constructor.getDefaultProps) {
+      Constructor.defaultProps = Constructor.getDefaultProps();
+    }
+
+    if ("production" !== process.env.NODE_ENV) {
+      // This is a tag to indicate that the use of these method names is ok,
+      // since it's used with createClass. If it's not, then it's likely a
+      // mistake so we'll warn you to use the static property, property
+      // initializer or constructor respectively.
+      if (Constructor.getDefaultProps) {
+        Constructor.getDefaultProps.isReactClassApproved = {};
+      }
+      if (Constructor.prototype.getInitialState) {
+        Constructor.prototype.getInitialState.isReactClassApproved = {};
+      }
+    }
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      Constructor.prototype.render,
+      'createClass(...): Class specification must implement a `render` method.'
+    ) : invariant(Constructor.prototype.render));
+
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        !Constructor.prototype.componentShouldUpdate,
+        '%s has a method called ' +
+        'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
+        'The name is phrased as a question because the function is ' +
+        'expected to return a value.',
+        spec.displayName || 'A component'
+      ) : null);
+    }
+
+    // Reduce time spent doing lookups by setting these on the prototype.
+    for (var methodName in ReactClassInterface) {
+      if (!Constructor.prototype[methodName]) {
+        Constructor.prototype[methodName] = null;
+      }
+    }
+
+    // Legacy hook
+    Constructor.type = Constructor;
+    if ("production" !== process.env.NODE_ENV) {
+      try {
+        Object.defineProperty(Constructor, 'type', typeDeprecationDescriptor);
+      } catch (x) {
+        // IE will fail on defineProperty (es5-shim/sham too)
+      }
+    }
+
+    return Constructor;
+  },
+
+  injection: {
+    injectMixin: function(mixin) {
+      injectedMixins.push(mixin);
+    }
+  }
+
+};
+
+module.exports = ReactClass;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./ReactComponent":35,"./ReactCurrentOwner":40,"./ReactElement":58,"./ReactErrorUtils":61,"./ReactInstanceMap":68,"./ReactLifeCycle":69,"./ReactPropTypeLocationNames":77,"./ReactPropTypeLocations":78,"./ReactUpdateQueue":87,"./invariant":136,"./keyMirror":141,"./keyOf":142,"./warning":155,"_process":157}],35:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponent
+ */
+
+'use strict';
+
+var ReactUpdateQueue = require("./ReactUpdateQueue");
+
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+/**
+ * Base class helpers for the updating state of a component.
+ */
+function ReactComponent(props, context) {
+  this.props = props;
+  this.context = context;
+}
+
+/**
+ * Sets a subset of the state. Always use this to mutate
+ * state. You should treat `this.state` as immutable.
+ *
+ * There is no guarantee that `this.state` will be immediately updated, so
+ * accessing `this.state` after calling this method may return the old value.
+ *
+ * There is no guarantee that calls to `setState` will run synchronously,
+ * as they may eventually be batched together.  You can provide an optional
+ * callback that will be executed when the call to setState is actually
+ * completed.
+ *
+ * When a function is provided to setState, it will be called at some point in
+ * the future (not synchronously). It will be called with the up to date
+ * component arguments (state, props, context). These values can be different
+ * from this.* because your function may be called after receiveProps but before
+ * shouldComponentUpdate, and this new state, props, and context will not yet be
+ * assigned to this.
+ *
+ * @param {object|function} partialState Next partial state or function to
+ *        produce next partial state to be merged with current state.
+ * @param {?function} callback Called after state is updated.
+ * @final
+ * @protected
+ */
+ReactComponent.prototype.setState = function(partialState, callback) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    typeof partialState === 'object' ||
+    typeof partialState === 'function' ||
+    partialState == null,
+    'setState(...): takes an object of state variables to update or a ' +
+    'function which returns an object of state variables.'
+  ) : invariant(typeof partialState === 'object' ||
+  typeof partialState === 'function' ||
+  partialState == null));
+  if ("production" !== process.env.NODE_ENV) {
+    ("production" !== process.env.NODE_ENV ? warning(
+      partialState != null,
+      'setState(...): You passed an undefined or null state object; ' +
+      'instead, use forceUpdate().'
+    ) : null);
+  }
+  ReactUpdateQueue.enqueueSetState(this, partialState);
+  if (callback) {
+    ReactUpdateQueue.enqueueCallback(this, callback);
+  }
+};
+
+/**
+ * Forces an update. This should only be invoked when it is known with
+ * certainty that we are **not** in a DOM transaction.
+ *
+ * You may want to call this when you know that some deeper aspect of the
+ * component's state has changed but `setState` was not called.
+ *
+ * This will not invoke `shouldComponentUpdate`, but it will invoke
+ * `componentWillUpdate` and `componentDidUpdate`.
+ *
+ * @param {?function} callback Called after update is complete.
+ * @final
+ * @protected
+ */
+ReactComponent.prototype.forceUpdate = function(callback) {
+  ReactUpdateQueue.enqueueForceUpdate(this);
+  if (callback) {
+    ReactUpdateQueue.enqueueCallback(this, callback);
+  }
+};
+
+/**
+ * Deprecated APIs. These APIs used to exist on classic React classes but since
+ * we would like to deprecate them, we're not going to move them over to this
+ * modern base class. Instead, we define a getter that warns if it's accessed.
+ */
+if ("production" !== process.env.NODE_ENV) {
+  var deprecatedAPIs = {
+    getDOMNode: 'getDOMNode',
+    isMounted: 'isMounted',
+    replaceProps: 'replaceProps',
+    replaceState: 'replaceState',
+    setProps: 'setProps'
+  };
+  var defineDeprecationWarning = function(methodName, displayName) {
+    try {
+      Object.defineProperty(ReactComponent.prototype, methodName, {
+        get: function() {
+          ("production" !== process.env.NODE_ENV ? warning(
+            false,
+            '%s(...) is deprecated in plain JavaScript React classes.',
+            displayName
+          ) : null);
+          return undefined;
+        }
+      });
+    } catch (x) {
+      // IE will fail on defineProperty (es5-shim/sham too)
+    }
+  };
+  for (var fnName in deprecatedAPIs) {
+    if (deprecatedAPIs.hasOwnProperty(fnName)) {
+      defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);
+    }
+  }
+}
+
+module.exports = ReactComponent;
+
+}).call(this,require('_process'))
+},{"./ReactUpdateQueue":87,"./invariant":136,"./warning":155,"_process":157}],36:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentBrowserEnvironment
+ */
+
+/*jslint evil: true */
+
+'use strict';
+
+var ReactDOMIDOperations = require("./ReactDOMIDOperations");
+var ReactMount = require("./ReactMount");
+
+/**
+ * Abstracts away all functionality of the reconciler that requires knowledge of
+ * the browser context. TODO: These callers should be refactored to avoid the
+ * need for this injection.
+ */
+var ReactComponentBrowserEnvironment = {
+
+  processChildrenUpdates:
+    ReactDOMIDOperations.dangerouslyProcessChildrenUpdates,
+
+  replaceNodeWithMarkupByID:
+    ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
+
+  /**
+   * If a particular environment requires that some resources be cleaned up,
+   * specify this in the injected Mixin. In the DOM, we would likely want to
+   * purge any cached node ID lookups.
+   *
+   * @private
+   */
+  unmountIDFromEnvironment: function(rootNodeID) {
+    ReactMount.purgeID(rootNodeID);
+  }
+
+};
+
+module.exports = ReactComponentBrowserEnvironment;
+
+},{"./ReactDOMIDOperations":45,"./ReactMount":71}],37:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentEnvironment
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+var injected = false;
+
+var ReactComponentEnvironment = {
+
+  /**
+   * Optionally injectable environment dependent cleanup hook. (server vs.
+   * browser etc). Example: A browser system caches DOM nodes based on component
+   * ID and must remove that cache entry when this instance is unmounted.
+   */
+  unmountIDFromEnvironment: null,
+
+  /**
+   * Optionally injectable hook for swapping out mount images in the middle of
+   * the tree.
+   */
+  replaceNodeWithMarkupByID: null,
+
+  /**
+   * Optionally injectable hook for processing a queue of child updates. Will
+   * later move into MultiChildComponents.
+   */
+  processChildrenUpdates: null,
+
+  injection: {
+    injectEnvironment: function(environment) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        !injected,
+        'ReactCompositeComponent: injectEnvironment() can only be called once.'
+      ) : invariant(!injected));
+      ReactComponentEnvironment.unmountIDFromEnvironment =
+        environment.unmountIDFromEnvironment;
+      ReactComponentEnvironment.replaceNodeWithMarkupByID =
+        environment.replaceNodeWithMarkupByID;
+      ReactComponentEnvironment.processChildrenUpdates =
+        environment.processChildrenUpdates;
+      injected = true;
+    }
+  }
+
+};
+
+module.exports = ReactComponentEnvironment;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],38:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCompositeComponent
+ */
+
+'use strict';
+
+var ReactComponentEnvironment = require("./ReactComponentEnvironment");
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactInstanceMap = require("./ReactInstanceMap");
+var ReactLifeCycle = require("./ReactLifeCycle");
+var ReactNativeComponent = require("./ReactNativeComponent");
+var ReactPerf = require("./ReactPerf");
+var ReactPropTypeLocations = require("./ReactPropTypeLocations");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+var ReactReconciler = require("./ReactReconciler");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var emptyObject = require("./emptyObject");
+var invariant = require("./invariant");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+var warning = require("./warning");
+
+function getDeclarationErrorAddendum(component) {
+  var owner = component._currentElement._owner || null;
+  if (owner) {
+    var name = owner.getName();
+    if (name) {
+      return ' Check the render method of `' + name + '`.';
+    }
+  }
+  return '';
+}
+
+/**
+ * ------------------ The Life-Cycle of a Composite Component ------------------
+ *
+ * - constructor: Initialization of state. The instance is now retained.
+ *   - componentWillMount
+ *   - render
+ *   - [children's constructors]
+ *     - [children's componentWillMount and render]
+ *     - [children's componentDidMount]
+ *     - componentDidMount
+ *
+ *       Update Phases:
+ *       - componentWillReceiveProps (only called if parent updated)
+ *       - shouldComponentUpdate
+ *         - componentWillUpdate
+ *           - render
+ *           - [children's constructors or receive props phases]
+ *         - componentDidUpdate
+ *
+ *     - componentWillUnmount
+ *     - [children's componentWillUnmount]
+ *   - [children destroyed]
+ * - (destroyed): The instance is now blank, released by React and ready for GC.
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+/**
+ * An incrementing ID assigned to each component when it is mounted. This is
+ * used to enforce the order in which `ReactUpdates` updates dirty components.
+ *
+ * @private
+ */
+var nextMountID = 1;
+
+/**
+ * @lends {ReactCompositeComponent.prototype}
+ */
+var ReactCompositeComponentMixin = {
+
+  /**
+   * Base constructor for all composite component.
+   *
+   * @param {ReactElement} element
+   * @final
+   * @internal
+   */
+  construct: function(element) {
+    this._currentElement = element;
+    this._rootNodeID = null;
+    this._instance = null;
+
+    // See ReactUpdateQueue
+    this._pendingElement = null;
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+
+    this._renderedComponent = null;
+
+    this._context = null;
+    this._mountOrder = 0;
+    this._isTopLevel = false;
+
+    // See ReactUpdates and ReactUpdateQueue.
+    this._pendingCallbacks = null;
+  },
+
+  /**
+   * Initializes the component, renders markup, and registers event listeners.
+   *
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {?string} Rendered markup to be inserted into the DOM.
+   * @final
+   * @internal
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._context = context;
+    this._mountOrder = nextMountID++;
+    this._rootNodeID = rootID;
+
+    var publicProps = this._processProps(this._currentElement.props);
+    var publicContext = this._processContext(this._currentElement._context);
+
+    var Component = ReactNativeComponent.getComponentClassForElement(
+      this._currentElement
+    );
+
+    // Initialize the public class
+    var inst = new Component(publicProps, publicContext);
+
+    if ("production" !== process.env.NODE_ENV) {
+      // This will throw later in _renderValidatedComponent, but add an early
+      // warning now to help debugging
+      ("production" !== process.env.NODE_ENV ? warning(
+        inst.render != null,
+        '%s(...): No `render` method found on the returned component ' +
+        'instance: you may have forgotten to define `render` in your ' +
+        'component or you may have accidentally tried to render an element ' +
+        'whose type is a function that isn\'t a React component.',
+        Component.displayName || Component.name || 'Component'
+      ) : null);
+    }
+
+    // These should be set up in the constructor, but as a convenience for
+    // simpler class abstractions, we set them up after the fact.
+    inst.props = publicProps;
+    inst.context = publicContext;
+    inst.refs = emptyObject;
+
+    this._instance = inst;
+
+    // Store a reference from the instance back to the internal representation
+    ReactInstanceMap.set(inst, this);
+
+    if ("production" !== process.env.NODE_ENV) {
+      this._warnIfContextsDiffer(this._currentElement._context, context);
+    }
+
+    if ("production" !== process.env.NODE_ENV) {
+      // Since plain JS classes are defined without any special initialization
+      // logic, we can not catch common errors early. Therefore, we have to
+      // catch them here, at initialization time, instead.
+      ("production" !== process.env.NODE_ENV ? warning(
+        !inst.getInitialState ||
+        inst.getInitialState.isReactClassApproved,
+        'getInitialState was defined on %s, a plain JavaScript class. ' +
+        'This is only supported for classes created using React.createClass. ' +
+        'Did you mean to define a state property instead?',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== process.env.NODE_ENV ? warning(
+        !inst.propTypes,
+        'propTypes was defined as an instance property on %s. Use a static ' +
+        'property to define propTypes instead.',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== process.env.NODE_ENV ? warning(
+        !inst.contextTypes,
+        'contextTypes was defined as an instance property on %s. Use a ' +
+        'static property to define contextTypes instead.',
+        this.getName() || 'a component'
+      ) : null);
+      ("production" !== process.env.NODE_ENV ? warning(
+        typeof inst.componentShouldUpdate !== 'function',
+        '%s has a method called ' +
+        'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
+        'The name is phrased as a question because the function is ' +
+        'expected to return a value.',
+        (this.getName() || 'A component')
+      ) : null);
+    }
+
+    var initialState = inst.state;
+    if (initialState === undefined) {
+      inst.state = initialState = null;
+    }
+    ("production" !== process.env.NODE_ENV ? invariant(
+      typeof initialState === 'object' && !Array.isArray(initialState),
+      '%s.state: must be set to an object or null',
+      this.getName() || 'ReactCompositeComponent'
+    ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState)));
+
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+
+    var renderedElement;
+
+    var previouslyMounting = ReactLifeCycle.currentlyMountingInstance;
+    ReactLifeCycle.currentlyMountingInstance = this;
+    try {
+      if (inst.componentWillMount) {
+        inst.componentWillMount();
+        // When mounting, calls to `setState` by `componentWillMount` will set
+        // `this._pendingStateQueue` without triggering a re-render.
+        if (this._pendingStateQueue) {
+          inst.state = this._processPendingState(inst.props, inst.context);
+        }
+      }
+
+      renderedElement = this._renderValidatedComponent();
+    } finally {
+      ReactLifeCycle.currentlyMountingInstance = previouslyMounting;
+    }
+
+    this._renderedComponent = this._instantiateReactComponent(
+      renderedElement,
+      this._currentElement.type // The wrapping type
+    );
+
+    var markup = ReactReconciler.mountComponent(
+      this._renderedComponent,
+      rootID,
+      transaction,
+      this._processChildContext(context)
+    );
+    if (inst.componentDidMount) {
+      transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
+    }
+
+    return markup;
+  },
+
+  /**
+   * Releases any resources allocated by `mountComponent`.
+   *
+   * @final
+   * @internal
+   */
+  unmountComponent: function() {
+    var inst = this._instance;
+
+    if (inst.componentWillUnmount) {
+      var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance;
+      ReactLifeCycle.currentlyUnmountingInstance = this;
+      try {
+        inst.componentWillUnmount();
+      } finally {
+        ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting;
+      }
+    }
+
+    ReactReconciler.unmountComponent(this._renderedComponent);
+    this._renderedComponent = null;
+
+    // Reset pending fields
+    this._pendingStateQueue = null;
+    this._pendingReplaceState = false;
+    this._pendingForceUpdate = false;
+    this._pendingCallbacks = null;
+    this._pendingElement = null;
+
+    // These fields do not really need to be reset since this object is no
+    // longer accessible.
+    this._context = null;
+    this._rootNodeID = null;
+
+    // Delete the reference from the instance to this internal representation
+    // which allow the internals to be properly cleaned up even if the user
+    // leaks a reference to the public instance.
+    ReactInstanceMap.remove(inst);
+
+    // Some existing components rely on inst.props even after they've been
+    // destroyed (in event handlers).
+    // TODO: inst.props = null;
+    // TODO: inst.state = null;
+    // TODO: inst.context = null;
+  },
+
+  /**
+   * Schedule a partial update to the props. Only used for internal testing.
+   *
+   * @param {object} partialProps Subset of the next props.
+   * @param {?function} callback Called after props are updated.
+   * @final
+   * @internal
+   */
+  _setPropsInternal: function(partialProps, callback) {
+    // This is a deoptimized path. We optimize for always having an element.
+    // This creates an extra internal element.
+    var element = this._pendingElement || this._currentElement;
+    this._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      assign({}, element.props, partialProps)
+    );
+    ReactUpdates.enqueueUpdate(this, callback);
+  },
+
+  /**
+   * Filters the context object to only contain keys specified in
+   * `contextTypes`
+   *
+   * @param {object} context
+   * @return {?object}
+   * @private
+   */
+  _maskContext: function(context) {
+    var maskedContext = null;
+    // This really should be getting the component class for the element,
+    // but we know that we're not going to need it for built-ins.
+    if (typeof this._currentElement.type === 'string') {
+      return emptyObject;
+    }
+    var contextTypes = this._currentElement.type.contextTypes;
+    if (!contextTypes) {
+      return emptyObject;
+    }
+    maskedContext = {};
+    for (var contextName in contextTypes) {
+      maskedContext[contextName] = context[contextName];
+    }
+    return maskedContext;
+  },
+
+  /**
+   * Filters the context object to only contain keys specified in
+   * `contextTypes`, and asserts that they are valid.
+   *
+   * @param {object} context
+   * @return {?object}
+   * @private
+   */
+  _processContext: function(context) {
+    var maskedContext = this._maskContext(context);
+    if ("production" !== process.env.NODE_ENV) {
+      var Component = ReactNativeComponent.getComponentClassForElement(
+        this._currentElement
+      );
+      if (Component.contextTypes) {
+        this._checkPropTypes(
+          Component.contextTypes,
+          maskedContext,
+          ReactPropTypeLocations.context
+        );
+      }
+    }
+    return maskedContext;
+  },
+
+  /**
+   * @param {object} currentContext
+   * @return {object}
+   * @private
+   */
+  _processChildContext: function(currentContext) {
+    var inst = this._instance;
+    var childContext = inst.getChildContext && inst.getChildContext();
+    if (childContext) {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        typeof inst.constructor.childContextTypes === 'object',
+        '%s.getChildContext(): childContextTypes must be defined in order to ' +
+        'use getChildContext().',
+        this.getName() || 'ReactCompositeComponent'
+      ) : invariant(typeof inst.constructor.childContextTypes === 'object'));
+      if ("production" !== process.env.NODE_ENV) {
+        this._checkPropTypes(
+          inst.constructor.childContextTypes,
+          childContext,
+          ReactPropTypeLocations.childContext
+        );
+      }
+      for (var name in childContext) {
+        ("production" !== process.env.NODE_ENV ? invariant(
+          name in inst.constructor.childContextTypes,
+          '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
+          this.getName() || 'ReactCompositeComponent',
+          name
+        ) : invariant(name in inst.constructor.childContextTypes));
+      }
+      return assign({}, currentContext, childContext);
+    }
+    return currentContext;
+  },
+
+  /**
+   * Processes props by setting default values for unspecified props and
+   * asserting that the props are valid. Does not mutate its argument; returns
+   * a new props object with defaults merged in.
+   *
+   * @param {object} newProps
+   * @return {object}
+   * @private
+   */
+  _processProps: function(newProps) {
+    if ("production" !== process.env.NODE_ENV) {
+      var Component = ReactNativeComponent.getComponentClassForElement(
+        this._currentElement
+      );
+      if (Component.propTypes) {
+        this._checkPropTypes(
+          Component.propTypes,
+          newProps,
+          ReactPropTypeLocations.prop
+        );
+      }
+    }
+    return newProps;
+  },
+
+  /**
+   * Assert that the props are valid
+   *
+   * @param {object} propTypes Map of prop name to a ReactPropType
+   * @param {object} props
+   * @param {string} location e.g. "prop", "context", "child context"
+   * @private
+   */
+  _checkPropTypes: function(propTypes, props, location) {
+    // TODO: Stop validating prop types here and only use the element
+    // validation.
+    var componentName = this.getName();
+    for (var propName in propTypes) {
+      if (propTypes.hasOwnProperty(propName)) {
+        var error;
+        try {
+          // This is intentionally an invariant that gets caught. It's the same
+          // behavior as without this statement except with a better message.
+          ("production" !== process.env.NODE_ENV ? invariant(
+            typeof propTypes[propName] === 'function',
+            '%s: %s type `%s` is invalid; it must be a function, usually ' +
+            'from React.PropTypes.',
+            componentName || 'React class',
+            ReactPropTypeLocationNames[location],
+            propName
+          ) : invariant(typeof propTypes[propName] === 'function'));
+          error = propTypes[propName](props, propName, componentName, location);
+        } catch (ex) {
+          error = ex;
+        }
+        if (error instanceof Error) {
+          // We may want to extend this logic for similar errors in
+          // React.render calls, so I'm abstracting it away into
+          // a function to minimize refactoring in the future
+          var addendum = getDeclarationErrorAddendum(this);
+
+          if (location === ReactPropTypeLocations.prop) {
+            // Preface gives us something to blacklist in warning module
+            ("production" !== process.env.NODE_ENV ? warning(
+              false,
+              'Failed Composite propType: %s%s',
+              error.message,
+              addendum
+            ) : null);
+          } else {
+            ("production" !== process.env.NODE_ENV ? warning(
+              false,
+              'Failed Context Types: %s%s',
+              error.message,
+              addendum
+            ) : null);
+          }
+        }
+      }
+    }
+  },
+
+  receiveComponent: function(nextElement, transaction, nextContext) {
+    var prevElement = this._currentElement;
+    var prevContext = this._context;
+
+    this._pendingElement = null;
+
+    this.updateComponent(
+      transaction,
+      prevElement,
+      nextElement,
+      prevContext,
+      nextContext
+    );
+  },
+
+  /**
+   * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate`
+   * is set, update the component.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  performUpdateIfNecessary: function(transaction) {
+    if (this._pendingElement != null) {
+      ReactReconciler.receiveComponent(
+        this,
+        this._pendingElement || this._currentElement,
+        transaction,
+        this._context
+      );
+    }
+
+    if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
+      if ("production" !== process.env.NODE_ENV) {
+        ReactElementValidator.checkAndWarnForMutatedProps(
+          this._currentElement
+        );
+      }
+
+      this.updateComponent(
+        transaction,
+        this._currentElement,
+        this._currentElement,
+        this._context,
+        this._context
+      );
+    }
+  },
+
+  /**
+   * Compare two contexts, warning if they are different
+   * TODO: Remove this check when owner-context is removed
+   */
+   _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) {
+    ownerBasedContext = this._maskContext(ownerBasedContext);
+    parentBasedContext = this._maskContext(parentBasedContext);
+    var parentKeys = Object.keys(parentBasedContext).sort();
+    var displayName = this.getName() || 'ReactCompositeComponent';
+    for (var i = 0; i < parentKeys.length; i++) {
+      var key = parentKeys[i];
+      ("production" !== process.env.NODE_ENV ? warning(
+        ownerBasedContext[key] === parentBasedContext[key],
+        'owner-based and parent-based contexts differ '  +
+        '(values: `%s` vs `%s`) for key (%s) while mounting %s ' +
+        '(see: http://fb.me/react-context-by-parent)',
+        ownerBasedContext[key],
+        parentBasedContext[key],
+        key,
+        displayName
+      ) : null);
+    }
+  },
+
+  /**
+   * Perform an update to a mounted component. The componentWillReceiveProps and
+   * shouldComponentUpdate methods are called, then (assuming the update isn't
+   * skipped) the remaining update lifecycle methods are called and the DOM
+   * representation is updated.
+   *
+   * By default, this implements React's rendering and reconciliation algorithm.
+   * Sophisticated clients may wish to override this.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @param {ReactElement} prevParentElement
+   * @param {ReactElement} nextParentElement
+   * @internal
+   * @overridable
+   */
+  updateComponent: function(
+    transaction,
+    prevParentElement,
+    nextParentElement,
+    prevUnmaskedContext,
+    nextUnmaskedContext
+  ) {
+    var inst = this._instance;
+
+    var nextContext = inst.context;
+    var nextProps = inst.props;
+
+    // Distinguish between a props update versus a simple state update
+    if (prevParentElement !== nextParentElement) {
+      nextContext = this._processContext(nextParentElement._context);
+      nextProps = this._processProps(nextParentElement.props);
+
+      if ("production" !== process.env.NODE_ENV) {
+        if (nextUnmaskedContext != null) {
+          this._warnIfContextsDiffer(
+            nextParentElement._context,
+            nextUnmaskedContext
+          );
+        }
+      }
+
+      // An update here will schedule an update but immediately set
+      // _pendingStateQueue which will ensure that any state updates gets
+      // immediately reconciled instead of waiting for the next batch.
+
+      if (inst.componentWillReceiveProps) {
+        inst.componentWillReceiveProps(nextProps, nextContext);
+      }
+    }
+
+    var nextState = this._processPendingState(nextProps, nextContext);
+
+    var shouldUpdate =
+      this._pendingForceUpdate ||
+      !inst.shouldComponentUpdate ||
+      inst.shouldComponentUpdate(nextProps, nextState, nextContext);
+
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        typeof shouldUpdate !== 'undefined',
+        '%s.shouldComponentUpdate(): Returned undefined instead of a ' +
+        'boolean value. Make sure to return true or false.',
+        this.getName() || 'ReactCompositeComponent'
+      ) : null);
+    }
+
+    if (shouldUpdate) {
+      this._pendingForceUpdate = false;
+      // Will set `this.props`, `this.state` and `this.context`.
+      this._performComponentUpdate(
+        nextParentElement,
+        nextProps,
+        nextState,
+        nextContext,
+        transaction,
+        nextUnmaskedContext
+      );
+    } else {
+      // If it's determined that a component should not update, we still want
+      // to set props and state but we shortcut the rest of the update.
+      this._currentElement = nextParentElement;
+      this._context = nextUnmaskedContext;
+      inst.props = nextProps;
+      inst.state = nextState;
+      inst.context = nextContext;
+    }
+  },
+
+  _processPendingState: function(props, context) {
+    var inst = this._instance;
+    var queue = this._pendingStateQueue;
+    var replace = this._pendingReplaceState;
+    this._pendingReplaceState = false;
+    this._pendingStateQueue = null;
+
+    if (!queue) {
+      return inst.state;
+    }
+
+    var nextState = assign({}, replace ? queue[0] : inst.state);
+    for (var i = replace ? 1 : 0; i < queue.length; i++) {
+      var partial = queue[i];
+      assign(
+        nextState,
+        typeof partial === 'function' ?
+          partial.call(inst, nextState, props, context) :
+          partial
+      );
+    }
+
+    return nextState;
+  },
+
+  /**
+   * Merges new props and state, notifies delegate methods of update and
+   * performs update.
+   *
+   * @param {ReactElement} nextElement Next element
+   * @param {object} nextProps Next public object to set as properties.
+   * @param {?object} nextState Next object to set as state.
+   * @param {?object} nextContext Next public object to set as context.
+   * @param {ReactReconcileTransaction} transaction
+   * @param {?object} unmaskedContext
+   * @private
+   */
+  _performComponentUpdate: function(
+    nextElement,
+    nextProps,
+    nextState,
+    nextContext,
+    transaction,
+    unmaskedContext
+  ) {
+    var inst = this._instance;
+
+    var prevProps = inst.props;
+    var prevState = inst.state;
+    var prevContext = inst.context;
+
+    if (inst.componentWillUpdate) {
+      inst.componentWillUpdate(nextProps, nextState, nextContext);
+    }
+
+    this._currentElement = nextElement;
+    this._context = unmaskedContext;
+    inst.props = nextProps;
+    inst.state = nextState;
+    inst.context = nextContext;
+
+    this._updateRenderedComponent(transaction, unmaskedContext);
+
+    if (inst.componentDidUpdate) {
+      transaction.getReactMountReady().enqueue(
+        inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext),
+        inst
+      );
+    }
+  },
+
+  /**
+   * Call the component's `render` method and update the DOM accordingly.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  _updateRenderedComponent: function(transaction, context) {
+    var prevComponentInstance = this._renderedComponent;
+    var prevRenderedElement = prevComponentInstance._currentElement;
+    var nextRenderedElement = this._renderValidatedComponent();
+    if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) {
+      ReactReconciler.receiveComponent(
+        prevComponentInstance,
+        nextRenderedElement,
+        transaction,
+        this._processChildContext(context)
+      );
+    } else {
+      // These two IDs are actually the same! But nothing should rely on that.
+      var thisID = this._rootNodeID;
+      var prevComponentID = prevComponentInstance._rootNodeID;
+      ReactReconciler.unmountComponent(prevComponentInstance);
+
+      this._renderedComponent = this._instantiateReactComponent(
+        nextRenderedElement,
+        this._currentElement.type
+      );
+      var nextMarkup = ReactReconciler.mountComponent(
+        this._renderedComponent,
+        thisID,
+        transaction,
+        context
+      );
+      this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup);
+    }
+  },
+
+  /**
+   * @protected
+   */
+  _replaceNodeWithMarkupByID: function(prevComponentID, nextMarkup) {
+    ReactComponentEnvironment.replaceNodeWithMarkupByID(
+      prevComponentID,
+      nextMarkup
+    );
+  },
+
+  /**
+   * @protected
+   */
+  _renderValidatedComponentWithoutOwnerOrContext: function() {
+    var inst = this._instance;
+    var renderedComponent = inst.render();
+    if ("production" !== process.env.NODE_ENV) {
+      // We allow auto-mocks to proceed as if they're returning null.
+      if (typeof renderedComponent === 'undefined' &&
+          inst.render._isMockFunction) {
+        // This is probably bad practice. Consider warning here and
+        // deprecating this convenience.
+        renderedComponent = null;
+      }
+    }
+
+    return renderedComponent;
+  },
+
+  /**
+   * @private
+   */
+  _renderValidatedComponent: function() {
+    var renderedComponent;
+    var previousContext = ReactContext.current;
+    ReactContext.current = this._processChildContext(
+      this._currentElement._context
+    );
+    ReactCurrentOwner.current = this;
+    try {
+      renderedComponent =
+        this._renderValidatedComponentWithoutOwnerOrContext();
+    } finally {
+      ReactContext.current = previousContext;
+      ReactCurrentOwner.current = null;
+    }
+    ("production" !== process.env.NODE_ENV ? invariant(
+      // TODO: An `isValidNode` function would probably be more appropriate
+      renderedComponent === null || renderedComponent === false ||
+      ReactElement.isValidElement(renderedComponent),
+      '%s.render(): A valid ReactComponent must be returned. You may have ' +
+        'returned undefined, an array or some other invalid object.',
+      this.getName() || 'ReactCompositeComponent'
+    ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate
+    renderedComponent === null || renderedComponent === false ||
+    ReactElement.isValidElement(renderedComponent)));
+    return renderedComponent;
+  },
+
+  /**
+   * Lazily allocates the refs object and stores `component` as `ref`.
+   *
+   * @param {string} ref Reference name.
+   * @param {component} component Component to store as `ref`.
+   * @final
+   * @private
+   */
+  attachRef: function(ref, component) {
+    var inst = this.getPublicInstance();
+    var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs;
+    refs[ref] = component.getPublicInstance();
+  },
+
+  /**
+   * Detaches a reference name.
+   *
+   * @param {string} ref Name to dereference.
+   * @final
+   * @private
+   */
+  detachRef: function(ref) {
+    var refs = this.getPublicInstance().refs;
+    delete refs[ref];
+  },
+
+  /**
+   * Get a text description of the component that can be used to identify it
+   * in error messages.
+   * @return {string} The name or null.
+   * @internal
+   */
+  getName: function() {
+    var type = this._currentElement.type;
+    var constructor = this._instance && this._instance.constructor;
+    return (
+      type.displayName || (constructor && constructor.displayName) ||
+      type.name || (constructor && constructor.name) ||
+      null
+    );
+  },
+
+  /**
+   * Get the publicly accessible representation of this component - i.e. what
+   * is exposed by refs and returned by React.render. Can be null for stateless
+   * components.
+   *
+   * @return {ReactComponent} the public component instance.
+   * @internal
+   */
+  getPublicInstance: function() {
+    return this._instance;
+  },
+
+  // Stub
+  _instantiateReactComponent: null
+
+};
+
+ReactPerf.measureMethods(
+  ReactCompositeComponentMixin,
+  'ReactCompositeComponent',
+  {
+    mountComponent: 'mountComponent',
+    updateComponent: 'updateComponent',
+    _renderValidatedComponent: '_renderValidatedComponent'
+  }
+);
+
+var ReactCompositeComponent = {
+
+  Mixin: ReactCompositeComponentMixin
+
+};
+
+module.exports = ReactCompositeComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./ReactComponentEnvironment":37,"./ReactContext":39,"./ReactCurrentOwner":40,"./ReactElement":58,"./ReactElementValidator":59,"./ReactInstanceMap":68,"./ReactLifeCycle":69,"./ReactNativeComponent":74,"./ReactPerf":76,"./ReactPropTypeLocationNames":77,"./ReactPropTypeLocations":78,"./ReactReconciler":82,"./ReactUpdates":88,"./emptyObject":116,"./invariant":136,"./shouldUpdateReactComponent":152,"./warning":155,"_process":157}],39:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactContext
+ */
+
+'use strict';
+
+var assign = require("./Object.assign");
+var emptyObject = require("./emptyObject");
+var warning = require("./warning");
+
+var didWarn = false;
+
+/**
+ * Keeps track of the current context.
+ *
+ * The context is automatically passed down the component ownership hierarchy
+ * and is accessible via `this.context` on ReactCompositeComponents.
+ */
+var ReactContext = {
+
+  /**
+   * @internal
+   * @type {object}
+   */
+  current: emptyObject,
+
+  /**
+   * Temporarily extends the current context while executing scopedCallback.
+   *
+   * A typical use case might look like
+   *
+   *  render: function() {
+   *    var children = ReactContext.withContext({foo: 'foo'}, () => (
+   *
+   *    ));
+   *    return <div>{children}</div>;
+   *  }
+   *
+   * @param {object} newContext New context to merge into the existing context
+   * @param {function} scopedCallback Callback to run with the new context
+   * @return {ReactComponent|array<ReactComponent>}
+   */
+  withContext: function(newContext, scopedCallback) {
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        didWarn,
+        'withContext is deprecated and will be removed in a future version. ' +
+        'Use a wrapper component with getChildContext instead.'
+      ) : null);
+
+      didWarn = true;
+    }
+
+    var result;
+    var previousContext = ReactContext.current;
+    ReactContext.current = assign({}, previousContext, newContext);
+    try {
+      result = scopedCallback();
+    } finally {
+      ReactContext.current = previousContext;
+    }
+    return result;
+  }
+
+};
+
+module.exports = ReactContext;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./emptyObject":116,"./warning":155,"_process":157}],40:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactCurrentOwner
+ */
+
+'use strict';
+
+/**
+ * Keeps track of the current owner.
+ *
+ * The current owner is the component who should own any components that are
+ * currently being constructed.
+ *
+ * The depth indicate how many composite components are above this render level.
+ */
+var ReactCurrentOwner = {
+
+  /**
+   * @internal
+   * @type {ReactComponent}
+   */
+  current: null
+
+};
+
+module.exports = ReactCurrentOwner;
+
+},{}],41:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOM
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+
+var mapObject = require("./mapObject");
+
+/**
+ * Create a factory that creates HTML tag elements.
+ *
+ * @param {string} tag Tag name (e.g. `div`).
+ * @private
+ */
+function createDOMFactory(tag) {
+  if ("production" !== process.env.NODE_ENV) {
+    return ReactElementValidator.createFactory(tag);
+  }
+  return ReactElement.createFactory(tag);
+}
+
+/**
+ * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
+ * This is also accessible via `React.DOM`.
+ *
+ * @public
+ */
+var ReactDOM = mapObject({
+  a: 'a',
+  abbr: 'abbr',
+  address: 'address',
+  area: 'area',
+  article: 'article',
+  aside: 'aside',
+  audio: 'audio',
+  b: 'b',
+  base: 'base',
+  bdi: 'bdi',
+  bdo: 'bdo',
+  big: 'big',
+  blockquote: 'blockquote',
+  body: 'body',
+  br: 'br',
+  button: 'button',
+  canvas: 'canvas',
+  caption: 'caption',
+  cite: 'cite',
+  code: 'code',
+  col: 'col',
+  colgroup: 'colgroup',
+  data: 'data',
+  datalist: 'datalist',
+  dd: 'dd',
+  del: 'del',
+  details: 'details',
+  dfn: 'dfn',
+  dialog: 'dialog',
+  div: 'div',
+  dl: 'dl',
+  dt: 'dt',
+  em: 'em',
+  embed: 'embed',
+  fieldset: 'fieldset',
+  figcaption: 'figcaption',
+  figure: 'figure',
+  footer: 'footer',
+  form: 'form',
+  h1: 'h1',
+  h2: 'h2',
+  h3: 'h3',
+  h4: 'h4',
+  h5: 'h5',
+  h6: 'h6',
+  head: 'head',
+  header: 'header',
+  hr: 'hr',
+  html: 'html',
+  i: 'i',
+  iframe: 'iframe',
+  img: 'img',
+  input: 'input',
+  ins: 'ins',
+  kbd: 'kbd',
+  keygen: 'keygen',
+  label: 'label',
+  legend: 'legend',
+  li: 'li',
+  link: 'link',
+  main: 'main',
+  map: 'map',
+  mark: 'mark',
+  menu: 'menu',
+  menuitem: 'menuitem',
+  meta: 'meta',
+  meter: 'meter',
+  nav: 'nav',
+  noscript: 'noscript',
+  object: 'object',
+  ol: 'ol',
+  optgroup: 'optgroup',
+  option: 'option',
+  output: 'output',
+  p: 'p',
+  param: 'param',
+  picture: 'picture',
+  pre: 'pre',
+  progress: 'progress',
+  q: 'q',
+  rp: 'rp',
+  rt: 'rt',
+  ruby: 'ruby',
+  s: 's',
+  samp: 'samp',
+  script: 'script',
+  section: 'section',
+  select: 'select',
+  small: 'small',
+  source: 'source',
+  span: 'span',
+  strong: 'strong',
+  style: 'style',
+  sub: 'sub',
+  summary: 'summary',
+  sup: 'sup',
+  table: 'table',
+  tbody: 'tbody',
+  td: 'td',
+  textarea: 'textarea',
+  tfoot: 'tfoot',
+  th: 'th',
+  thead: 'thead',
+  time: 'time',
+  title: 'title',
+  tr: 'tr',
+  track: 'track',
+  u: 'u',
+  ul: 'ul',
+  'var': 'var',
+  video: 'video',
+  wbr: 'wbr',
+
+  // SVG
+  circle: 'circle',
+  defs: 'defs',
+  ellipse: 'ellipse',
+  g: 'g',
+  line: 'line',
+  linearGradient: 'linearGradient',
+  mask: 'mask',
+  path: 'path',
+  pattern: 'pattern',
+  polygon: 'polygon',
+  polyline: 'polyline',
+  radialGradient: 'radialGradient',
+  rect: 'rect',
+  stop: 'stop',
+  svg: 'svg',
+  text: 'text',
+  tspan: 'tspan'
+
+}, createDOMFactory);
+
+module.exports = ReactDOM;
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./ReactElementValidator":59,"./mapObject":143,"_process":157}],42:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMButton
+ */
+
+'use strict';
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var keyMirror = require("./keyMirror");
+
+var button = ReactElement.createFactory('button');
+
+var mouseListenerNames = keyMirror({
+  onClick: true,
+  onDoubleClick: true,
+  onMouseDown: true,
+  onMouseMove: true,
+  onMouseUp: true,
+  onClickCapture: true,
+  onDoubleClickCapture: true,
+  onMouseDownCapture: true,
+  onMouseMoveCapture: true,
+  onMouseUpCapture: true
+});
+
+/**
+ * Implements a <button> native component that does not receive mouse events
+ * when `disabled` is set.
+ */
+var ReactDOMButton = ReactClass.createClass({
+  displayName: 'ReactDOMButton',
+  tagName: 'BUTTON',
+
+  mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
+
+  render: function() {
+    var props = {};
+
+    // Copy the props; except the mouse listeners if we're disabled
+    for (var key in this.props) {
+      if (this.props.hasOwnProperty(key) &&
+          (!this.props.disabled || !mouseListenerNames[key])) {
+        props[key] = this.props[key];
+      }
+    }
+
+    return button(props, this.props.children);
+  }
+
+});
+
+module.exports = ReactDOMButton;
+
+},{"./AutoFocusMixin":2,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58,"./keyMirror":141}],43:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMComponent
+ * @typechecks static-only
+ */
+
+/* global hasOwnProperty:true */
+
+'use strict';
+
+var CSSPropertyOperations = require("./CSSPropertyOperations");
+var DOMProperty = require("./DOMProperty");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactComponentBrowserEnvironment =
+  require("./ReactComponentBrowserEnvironment");
+var ReactMount = require("./ReactMount");
+var ReactMultiChild = require("./ReactMultiChild");
+var ReactPerf = require("./ReactPerf");
+
+var assign = require("./Object.assign");
+var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
+var invariant = require("./invariant");
+var isEventSupported = require("./isEventSupported");
+var keyOf = require("./keyOf");
+var warning = require("./warning");
+
+var deleteListener = ReactBrowserEventEmitter.deleteListener;
+var listenTo = ReactBrowserEventEmitter.listenTo;
+var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;
+
+// For quickly matching children type, to test if can be treated as content.
+var CONTENT_TYPES = {'string': true, 'number': true};
+
+var STYLE = keyOf({style: null});
+
+var ELEMENT_NODE_TYPE = 1;
+
+/**
+ * Optionally injectable operations for mutating the DOM
+ */
+var BackendIDOperations = null;
+
+/**
+ * @param {?object} props
+ */
+function assertValidProps(props) {
+  if (!props) {
+    return;
+  }
+  // Note the use of `==` which checks for null or undefined.
+  if (props.dangerouslySetInnerHTML != null) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      props.children == null,
+      'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
+    ) : invariant(props.children == null));
+    ("production" !== process.env.NODE_ENV ? invariant(
+      props.dangerouslySetInnerHTML.__html != null,
+      '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' +
+      'Please visit http://fb.me/react-invariant-dangerously-set-inner-html ' +
+      'for more information.'
+    ) : invariant(props.dangerouslySetInnerHTML.__html != null));
+  }
+  if ("production" !== process.env.NODE_ENV) {
+    ("production" !== process.env.NODE_ENV ? warning(
+      props.innerHTML == null,
+      'Directly setting property `innerHTML` is not permitted. ' +
+      'For more information, lookup documentation on `dangerouslySetInnerHTML`.'
+    ) : null);
+    ("production" !== process.env.NODE_ENV ? warning(
+      !props.contentEditable || props.children == null,
+      'A component is `contentEditable` and contains `children` managed by ' +
+      'React. It is now your responsibility to guarantee that none of ' +
+      'those nodes are unexpectedly modified or duplicated. This is ' +
+      'probably not intentional.'
+    ) : null);
+  }
+  ("production" !== process.env.NODE_ENV ? invariant(
+    props.style == null || typeof props.style === 'object',
+    'The `style` prop expects a mapping from style properties to values, ' +
+    'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' +
+    'using JSX.'
+  ) : invariant(props.style == null || typeof props.style === 'object'));
+}
+
+function putListener(id, registrationName, listener, transaction) {
+  if ("production" !== process.env.NODE_ENV) {
+    // IE8 has no API for event capturing and the `onScroll` event doesn't
+    // bubble.
+    ("production" !== process.env.NODE_ENV ? warning(
+      registrationName !== 'onScroll' || isEventSupported('scroll', true),
+      'This browser doesn\'t support the `onScroll` event'
+    ) : null);
+  }
+  var container = ReactMount.findReactContainerForID(id);
+  if (container) {
+    var doc = container.nodeType === ELEMENT_NODE_TYPE ?
+      container.ownerDocument :
+      container;
+    listenTo(registrationName, doc);
+  }
+  transaction.getPutListenerQueue().enqueuePutListener(
+    id,
+    registrationName,
+    listener
+  );
+}
+
+// For HTML, certain tags should omit their close tag. We keep a whitelist for
+// those special cased tags.
+
+var omittedCloseTags = {
+  'area': true,
+  'base': true,
+  'br': true,
+  'col': true,
+  'embed': true,
+  'hr': true,
+  'img': true,
+  'input': true,
+  'keygen': true,
+  'link': true,
+  'meta': true,
+  'param': true,
+  'source': true,
+  'track': true,
+  'wbr': true
+  // NOTE: menuitem's close tag should be omitted, but that causes problems.
+};
+
+// We accept any tag to be rendered but since this gets injected into abitrary
+// HTML, we want to make sure that it's a safe tag.
+// http://www.w3.org/TR/REC-xml/#NT-Name
+
+var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
+var validatedTagCache = {};
+var hasOwnProperty = {}.hasOwnProperty;
+
+function validateDangerousTag(tag) {
+  if (!hasOwnProperty.call(validatedTagCache, tag)) {
+    ("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
+    validatedTagCache[tag] = true;
+  }
+}
+
+/**
+ * Creates a new React class that is idempotent and capable of containing other
+ * React components. It accepts event listeners and DOM properties that are
+ * valid according to `DOMProperty`.
+ *
+ *  - Event listeners: `onClick`, `onMouseDown`, etc.
+ *  - DOM properties: `className`, `name`, `title`, etc.
+ *
+ * The `style` property functions differently from the DOM API. It accepts an
+ * object mapping of style properties to values.
+ *
+ * @constructor ReactDOMComponent
+ * @extends ReactMultiChild
+ */
+function ReactDOMComponent(tag) {
+  validateDangerousTag(tag);
+  this._tag = tag;
+  this._renderedChildren = null;
+  this._previousStyleCopy = null;
+  this._rootNodeID = null;
+}
+
+ReactDOMComponent.displayName = 'ReactDOMComponent';
+
+ReactDOMComponent.Mixin = {
+
+  construct: function(element) {
+    this._currentElement = element;
+  },
+
+  /**
+   * Generates root tag markup then recurses. This method has side effects and
+   * is not idempotent.
+   *
+   * @internal
+   * @param {string} rootID The root DOM ID for this node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} The computed markup.
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._rootNodeID = rootID;
+    assertValidProps(this._currentElement.props);
+    var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
+    return (
+      this._createOpenTagMarkupAndPutListeners(transaction) +
+      this._createContentMarkup(transaction, context) +
+      closeTag
+    );
+  },
+
+  /**
+   * Creates markup for the open tag and all attributes.
+   *
+   * This method has side effects because events get registered.
+   *
+   * Iterating over object properties is faster than iterating over arrays.
+   * @see http://jsperf.com/obj-vs-arr-iteration
+   *
+   * @private
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} Markup of opening tag.
+   */
+  _createOpenTagMarkupAndPutListeners: function(transaction) {
+    var props = this._currentElement.props;
+    var ret = '<' + this._tag;
+
+    for (var propKey in props) {
+      if (!props.hasOwnProperty(propKey)) {
+        continue;
+      }
+      var propValue = props[propKey];
+      if (propValue == null) {
+        continue;
+      }
+      if (registrationNameModules.hasOwnProperty(propKey)) {
+        putListener(this._rootNodeID, propKey, propValue, transaction);
+      } else {
+        if (propKey === STYLE) {
+          if (propValue) {
+            propValue = this._previousStyleCopy = assign({}, props.style);
+          }
+          propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
+        }
+        var markup =
+          DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
+        if (markup) {
+          ret += ' ' + markup;
+        }
+      }
+    }
+
+    // For static pages, no need to put React ID and checksum. Saves lots of
+    // bytes.
+    if (transaction.renderToStaticMarkup) {
+      return ret + '>';
+    }
+
+    var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
+    return ret + ' ' + markupForID + '>';
+  },
+
+  /**
+   * Creates markup for the content between the tags.
+   *
+   * @private
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @param {object} context
+   * @return {string} Content markup.
+   */
+  _createContentMarkup: function(transaction, context) {
+    var prefix = '';
+    if (this._tag === 'listing' ||
+        this._tag === 'pre' ||
+        this._tag === 'textarea') {
+      // Add an initial newline because browsers ignore the first newline in
+      // a <listing>, <pre>, or <textarea> as an "authoring convenience" -- see
+      // https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inbody.
+      prefix = '\n';
+    }
+
+    var props = this._currentElement.props;
+
+    // Intentional use of != to avoid catching zero/false.
+    var innerHTML = props.dangerouslySetInnerHTML;
+    if (innerHTML != null) {
+      if (innerHTML.__html != null) {
+        return prefix + innerHTML.__html;
+      }
+    } else {
+      var contentToUse =
+        CONTENT_TYPES[typeof props.children] ? props.children : null;
+      var childrenToUse = contentToUse != null ? null : props.children;
+      if (contentToUse != null) {
+        return prefix + escapeTextContentForBrowser(contentToUse);
+      } else if (childrenToUse != null) {
+        var mountImages = this.mountChildren(
+          childrenToUse,
+          transaction,
+          context
+        );
+        return prefix + mountImages.join('');
+      }
+    }
+    return prefix;
+  },
+
+  receiveComponent: function(nextElement, transaction, context) {
+    var prevElement = this._currentElement;
+    this._currentElement = nextElement;
+    this.updateComponent(transaction, prevElement, nextElement, context);
+  },
+
+  /**
+   * Updates a native DOM component after it has already been allocated and
+   * attached to the DOM. Reconciles the root DOM node, then recurses.
+   *
+   * @param {ReactReconcileTransaction} transaction
+   * @param {ReactElement} prevElement
+   * @param {ReactElement} nextElement
+   * @internal
+   * @overridable
+   */
+  updateComponent: function(transaction, prevElement, nextElement, context) {
+    assertValidProps(this._currentElement.props);
+    this._updateDOMProperties(prevElement.props, transaction);
+    this._updateDOMChildren(prevElement.props, transaction, context);
+  },
+
+  /**
+   * Reconciles the properties by detecting differences in property values and
+   * updating the DOM as necessary. This function is probably the single most
+   * critical path for performance optimization.
+   *
+   * TODO: Benchmark whether checking for changed values in memory actually
+   *       improves performance (especially statically positioned elements).
+   * TODO: Benchmark the effects of putting this at the top since 99% of props
+   *       do not change for a given reconciliation.
+   * TODO: Benchmark areas that can be improved with caching.
+   *
+   * @private
+   * @param {object} lastProps
+   * @param {ReactReconcileTransaction} transaction
+   */
+  _updateDOMProperties: function(lastProps, transaction) {
+    var nextProps = this._currentElement.props;
+    var propKey;
+    var styleName;
+    var styleUpdates;
+    for (propKey in lastProps) {
+      if (nextProps.hasOwnProperty(propKey) ||
+         !lastProps.hasOwnProperty(propKey)) {
+        continue;
+      }
+      if (propKey === STYLE) {
+        var lastStyle = this._previousStyleCopy;
+        for (styleName in lastStyle) {
+          if (lastStyle.hasOwnProperty(styleName)) {
+            styleUpdates = styleUpdates || {};
+            styleUpdates[styleName] = '';
+          }
+        }
+        this._previousStyleCopy = null;
+      } else if (registrationNameModules.hasOwnProperty(propKey)) {
+        deleteListener(this._rootNodeID, propKey);
+      } else if (
+          DOMProperty.isStandardName[propKey] ||
+          DOMProperty.isCustomAttribute(propKey)) {
+        BackendIDOperations.deletePropertyByID(
+          this._rootNodeID,
+          propKey
+        );
+      }
+    }
+    for (propKey in nextProps) {
+      var nextProp = nextProps[propKey];
+      var lastProp = propKey === STYLE ?
+        this._previousStyleCopy :
+        lastProps[propKey];
+      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
+        continue;
+      }
+      if (propKey === STYLE) {
+        if (nextProp) {
+          nextProp = this._previousStyleCopy = assign({}, nextProp);
+        }
+        if (lastProp) {
+          // Unset styles on `lastProp` but not on `nextProp`.
+          for (styleName in lastProp) {
+            if (lastProp.hasOwnProperty(styleName) &&
+                (!nextProp || !nextProp.hasOwnProperty(styleName))) {
+              styleUpdates = styleUpdates || {};
+              styleUpdates[styleName] = '';
+            }
+          }
+          // Update styles that changed since `lastProp`.
+          for (styleName in nextProp) {
+            if (nextProp.hasOwnProperty(styleName) &&
+                lastProp[styleName] !== nextProp[styleName]) {
+              styleUpdates = styleUpdates || {};
+              styleUpdates[styleName] = nextProp[styleName];
+            }
+          }
+        } else {
+          // Relies on `updateStylesByID` not mutating `styleUpdates`.
+          styleUpdates = nextProp;
+        }
+      } else if (registrationNameModules.hasOwnProperty(propKey)) {
+        putListener(this._rootNodeID, propKey, nextProp, transaction);
+      } else if (
+          DOMProperty.isStandardName[propKey] ||
+          DOMProperty.isCustomAttribute(propKey)) {
+        BackendIDOperations.updatePropertyByID(
+          this._rootNodeID,
+          propKey,
+          nextProp
+        );
+      }
+    }
+    if (styleUpdates) {
+      BackendIDOperations.updateStylesByID(
+        this._rootNodeID,
+        styleUpdates
+      );
+    }
+  },
+
+  /**
+   * Reconciles the children with the various properties that affect the
+   * children content.
+   *
+   * @param {object} lastProps
+   * @param {ReactReconcileTransaction} transaction
+   */
+  _updateDOMChildren: function(lastProps, transaction, context) {
+    var nextProps = this._currentElement.props;
+
+    var lastContent =
+      CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
+    var nextContent =
+      CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;
+
+    var lastHtml =
+      lastProps.dangerouslySetInnerHTML &&
+      lastProps.dangerouslySetInnerHTML.__html;
+    var nextHtml =
+      nextProps.dangerouslySetInnerHTML &&
+      nextProps.dangerouslySetInnerHTML.__html;
+
+    // Note the use of `!=` which checks for null or undefined.
+    var lastChildren = lastContent != null ? null : lastProps.children;
+    var nextChildren = nextContent != null ? null : nextProps.children;
+
+    // If we're switching from children to content/html or vice versa, remove
+    // the old content
+    var lastHasContentOrHtml = lastContent != null || lastHtml != null;
+    var nextHasContentOrHtml = nextContent != null || nextHtml != null;
+    if (lastChildren != null && nextChildren == null) {
+      this.updateChildren(null, transaction, context);
+    } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
+      this.updateTextContent('');
+    }
+
+    if (nextContent != null) {
+      if (lastContent !== nextContent) {
+        this.updateTextContent('' + nextContent);
+      }
+    } else if (nextHtml != null) {
+      if (lastHtml !== nextHtml) {
+        BackendIDOperations.updateInnerHTMLByID(
+          this._rootNodeID,
+          nextHtml
+        );
+      }
+    } else if (nextChildren != null) {
+      this.updateChildren(nextChildren, transaction, context);
+    }
+  },
+
+  /**
+   * Destroys all event registrations for this instance. Does not remove from
+   * the DOM. That must be done by the parent.
+   *
+   * @internal
+   */
+  unmountComponent: function() {
+    this.unmountChildren();
+    ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
+    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
+    this._rootNodeID = null;
+  }
+
+};
+
+ReactPerf.measureMethods(ReactDOMComponent, 'ReactDOMComponent', {
+  mountComponent: 'mountComponent',
+  updateComponent: 'updateComponent'
+});
+
+assign(
+  ReactDOMComponent.prototype,
+  ReactDOMComponent.Mixin,
+  ReactMultiChild.Mixin
+);
+
+ReactDOMComponent.injection = {
+  injectIDOperations: function(IDOperations) {
+    ReactDOMComponent.BackendIDOperations = BackendIDOperations = IDOperations;
+  }
+};
+
+module.exports = ReactDOMComponent;
+
+}).call(this,require('_process'))
+},{"./CSSPropertyOperations":5,"./DOMProperty":10,"./DOMPropertyOperations":11,"./Object.assign":27,"./ReactBrowserEventEmitter":31,"./ReactComponentBrowserEnvironment":36,"./ReactMount":71,"./ReactMultiChild":72,"./ReactPerf":76,"./escapeTextContentForBrowser":117,"./invariant":136,"./isEventSupported":137,"./keyOf":142,"./warning":155,"_process":157}],44:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMForm
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var LocalEventTrapMixin = require("./LocalEventTrapMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var form = ReactElement.createFactory('form');
+
+/**
+ * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
+ * to capture it on the <form> element itself. There are lots of hacks we could
+ * do to accomplish this, but the most reliable is to make <form> a
+ * composite component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMForm = ReactClass.createClass({
+  displayName: 'ReactDOMForm',
+  tagName: 'FORM',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
+    // `jshint` fails to parse JSX so in order for linting to work in the open
+    // source repo, we need to just use `ReactDOM.form`.
+    return form(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
+  }
+});
+
+module.exports = ReactDOMForm;
+
+},{"./EventConstants":15,"./LocalEventTrapMixin":25,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58}],45:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMIDOperations
+ * @typechecks static-only
+ */
+
+/*jslint evil: true */
+
+'use strict';
+
+var CSSPropertyOperations = require("./CSSPropertyOperations");
+var DOMChildrenOperations = require("./DOMChildrenOperations");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+
+var invariant = require("./invariant");
+var setInnerHTML = require("./setInnerHTML");
+
+/**
+ * Errors for properties that should not be updated with `updatePropertyById()`.
+ *
+ * @type {object}
+ * @private
+ */
+var INVALID_PROPERTY_ERRORS = {
+  dangerouslySetInnerHTML:
+    '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
+  style: '`style` must be set using `updateStylesByID()`.'
+};
+
+/**
+ * Operations used to process updates to DOM nodes. This is made injectable via
+ * `ReactDOMComponent.BackendIDOperations`.
+ */
+var ReactDOMIDOperations = {
+
+  /**
+   * Updates a DOM node with new property values. This should only be used to
+   * update DOM properties in `DOMProperty`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} name A valid property name, see `DOMProperty`.
+   * @param {*} value New value of the property.
+   * @internal
+   */
+  updatePropertyByID: function(id, name, value) {
+    var node = ReactMount.getNode(id);
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+      'updatePropertyByID(...): %s',
+      INVALID_PROPERTY_ERRORS[name]
+    ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+
+    // If we're updating to null or undefined, we should remove the property
+    // from the DOM node instead of inadvertantly setting to a string. This
+    // brings us in line with the same behavior we have on initial render.
+    if (value != null) {
+      DOMPropertyOperations.setValueForProperty(node, name, value);
+    } else {
+      DOMPropertyOperations.deleteValueForProperty(node, name);
+    }
+  },
+
+  /**
+   * Updates a DOM node to remove a property. This should only be used to remove
+   * DOM properties in `DOMProperty`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} name A property name to remove, see `DOMProperty`.
+   * @internal
+   */
+  deletePropertyByID: function(id, name, value) {
+    var node = ReactMount.getNode(id);
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
+      'updatePropertyByID(...): %s',
+      INVALID_PROPERTY_ERRORS[name]
+    ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
+    DOMPropertyOperations.deleteValueForProperty(node, name, value);
+  },
+
+  /**
+   * Updates a DOM node with new style values. If a value is specified as '',
+   * the corresponding style property will be unset.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {object} styles Mapping from styles to values.
+   * @internal
+   */
+  updateStylesByID: function(id, styles) {
+    var node = ReactMount.getNode(id);
+    CSSPropertyOperations.setValueForStyles(node, styles);
+  },
+
+  /**
+   * Updates a DOM node's innerHTML.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} html An HTML string.
+   * @internal
+   */
+  updateInnerHTMLByID: function(id, html) {
+    var node = ReactMount.getNode(id);
+    setInnerHTML(node, html);
+  },
+
+  /**
+   * Updates a DOM node's text content set by `props.content`.
+   *
+   * @param {string} id ID of the node to update.
+   * @param {string} content Text content.
+   * @internal
+   */
+  updateTextContentByID: function(id, content) {
+    var node = ReactMount.getNode(id);
+    DOMChildrenOperations.updateTextContent(node, content);
+  },
+
+  /**
+   * Replaces a DOM node that exists in the document with markup.
+   *
+   * @param {string} id ID of child to be replaced.
+   * @param {string} markup Dangerous markup to inject in place of child.
+   * @internal
+   * @see {Danger.dangerouslyReplaceNodeWithMarkup}
+   */
+  dangerouslyReplaceNodeWithMarkupByID: function(id, markup) {
+    var node = ReactMount.getNode(id);
+    DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
+  },
+
+  /**
+   * Updates a component's children by processing a series of updates.
+   *
+   * @param {array<object>} updates List of update configurations.
+   * @param {array<string>} markup List of markup strings.
+   * @internal
+   */
+  dangerouslyProcessChildrenUpdates: function(updates, markup) {
+    for (var i = 0; i < updates.length; i++) {
+      updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
+    }
+    DOMChildrenOperations.processUpdates(updates, markup);
+  }
+};
+
+ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', {
+  updatePropertyByID: 'updatePropertyByID',
+  deletePropertyByID: 'deletePropertyByID',
+  updateStylesByID: 'updateStylesByID',
+  updateInnerHTMLByID: 'updateInnerHTMLByID',
+  updateTextContentByID: 'updateTextContentByID',
+  dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID',
+  dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates'
+});
+
+module.exports = ReactDOMIDOperations;
+
+}).call(this,require('_process'))
+},{"./CSSPropertyOperations":5,"./DOMChildrenOperations":9,"./DOMPropertyOperations":11,"./ReactMount":71,"./ReactPerf":76,"./invariant":136,"./setInnerHTML":149,"_process":157}],46:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMIframe
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var LocalEventTrapMixin = require("./LocalEventTrapMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var iframe = ReactElement.createFactory('iframe');
+
+/**
+ * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
+ * capture it on the <iframe> element itself. There are lots of hacks we could
+ * do to accomplish this, but the most reliable is to make <iframe> a composite
+ * component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMIframe = ReactClass.createClass({
+  displayName: 'ReactDOMIframe',
+  tagName: 'IFRAME',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    return iframe(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
+  }
+});
+
+module.exports = ReactDOMIframe;
+
+},{"./EventConstants":15,"./LocalEventTrapMixin":25,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58}],47:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMImg
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var LocalEventTrapMixin = require("./LocalEventTrapMixin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var img = ReactElement.createFactory('img');
+
+/**
+ * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
+ * capture it on the <img> element itself. There are lots of hacks we could do
+ * to accomplish this, but the most reliable is to make <img> a composite
+ * component and use `componentDidMount` to attach the event handlers.
+ */
+var ReactDOMImg = ReactClass.createClass({
+  displayName: 'ReactDOMImg',
+  tagName: 'IMG',
+
+  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],
+
+  render: function() {
+    return img(this.props);
+  },
+
+  componentDidMount: function() {
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
+    this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
+  }
+});
+
+module.exports = ReactDOMImg;
+
+},{"./EventConstants":15,"./LocalEventTrapMixin":25,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58}],48:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMInput
+ */
+
+'use strict';
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+var ReactMount = require("./ReactMount");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+var input = ReactElement.createFactory('input');
+
+var instancesByReactID = {};
+
+function forceUpdateIfMounted() {
+  /*jshint validthis:true */
+  if (this.isMounted()) {
+    this.forceUpdate();
+  }
+}
+
+/**
+ * Implements an <input> native component that allows setting these optional
+ * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
+ *
+ * If `checked` or `value` are not supplied (or null/undefined), user actions
+ * that affect the checked state or value will trigger updates to the element.
+ *
+ * If they are supplied (and not null/undefined), the rendered element will not
+ * trigger updates to the element. Instead, the props must change in order for
+ * the rendered element to be updated.
+ *
+ * The rendered element will be initialized as unchecked (or `defaultChecked`)
+ * with an empty value (or `defaultValue`).
+ *
+ * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
+ */
+var ReactDOMInput = ReactClass.createClass({
+  displayName: 'ReactDOMInput',
+  tagName: 'INPUT',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  getInitialState: function() {
+    var defaultValue = this.props.defaultValue;
+    return {
+      initialChecked: this.props.defaultChecked || false,
+      initialValue: defaultValue != null ? defaultValue : null
+    };
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    props.defaultChecked = null;
+    props.defaultValue = null;
+
+    var value = LinkedValueUtils.getValue(this);
+    props.value = value != null ? value : this.state.initialValue;
+
+    var checked = LinkedValueUtils.getChecked(this);
+    props.checked = checked != null ? checked : this.state.initialChecked;
+
+    props.onChange = this._handleChange;
+
+    return input(props, this.props.children);
+  },
+
+  componentDidMount: function() {
+    var id = ReactMount.getID(this.getDOMNode());
+    instancesByReactID[id] = this;
+  },
+
+  componentWillUnmount: function() {
+    var rootNode = this.getDOMNode();
+    var id = ReactMount.getID(rootNode);
+    delete instancesByReactID[id];
+  },
+
+  componentDidUpdate: function(prevProps, prevState, prevContext) {
+    var rootNode = this.getDOMNode();
+    if (this.props.checked != null) {
+      DOMPropertyOperations.setValueForProperty(
+        rootNode,
+        'checked',
+        this.props.checked || false
+      );
+    }
+
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      // Cast `value` to a string to ensure the value is set correctly. While
+      // browsers typically do this as necessary, jsdom doesn't.
+      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+    // Here we use asap to wait until all updates have propagated, which
+    // is important when using controlled components within layers:
+    // https://github.com/facebook/react/issues/1698
+    ReactUpdates.asap(forceUpdateIfMounted, this);
+
+    var name = this.props.name;
+    if (this.props.type === 'radio' && name != null) {
+      var rootNode = this.getDOMNode();
+      var queryRoot = rootNode;
+
+      while (queryRoot.parentNode) {
+        queryRoot = queryRoot.parentNode;
+      }
+
+      // If `rootNode.form` was non-null, then we could try `form.elements`,
+      // but that sometimes behaves strangely in IE8. We could also try using
+      // `form.getElementsByName`, but that will only return direct children
+      // and won't include inputs that use the HTML5 `form=` attribute. Since
+      // the input might not even be in a form, let's just use the global
+      // `querySelectorAll` to ensure we don't miss anything.
+      var group = queryRoot.querySelectorAll(
+        'input[name=' + JSON.stringify('' + name) + '][type="radio"]');
+
+      for (var i = 0, groupLen = group.length; i < groupLen; i++) {
+        var otherNode = group[i];
+        if (otherNode === rootNode ||
+            otherNode.form !== rootNode.form) {
+          continue;
+        }
+        var otherID = ReactMount.getID(otherNode);
+        ("production" !== process.env.NODE_ENV ? invariant(
+          otherID,
+          'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
+          'same `name` is not supported.'
+        ) : invariant(otherID));
+        var otherInstance = instancesByReactID[otherID];
+        ("production" !== process.env.NODE_ENV ? invariant(
+          otherInstance,
+          'ReactDOMInput: Unknown radio button ID %s.',
+          otherID
+        ) : invariant(otherInstance));
+        // If this is a controlled radio button group, forcing the input that
+        // was previously checked to update will cause it to be come re-checked
+        // as appropriate.
+        ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
+      }
+    }
+
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMInput;
+
+}).call(this,require('_process'))
+},{"./AutoFocusMixin":2,"./DOMPropertyOperations":11,"./LinkedValueUtils":24,"./Object.assign":27,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58,"./ReactMount":71,"./ReactUpdates":88,"./invariant":136,"_process":157}],49:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMOption
+ */
+
+'use strict';
+
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var warning = require("./warning");
+
+var option = ReactElement.createFactory('option');
+
+/**
+ * Implements an <option> native component that warns when `selected` is set.
+ */
+var ReactDOMOption = ReactClass.createClass({
+  displayName: 'ReactDOMOption',
+  tagName: 'OPTION',
+
+  mixins: [ReactBrowserComponentMixin],
+
+  componentWillMount: function() {
+    // TODO (yungsters): Remove support for `selected` in <option>.
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        this.props.selected == null,
+        'Use the `defaultValue` or `value` props on <select> instead of ' +
+        'setting `selected` on <option>.'
+      ) : null);
+    }
+  },
+
+  render: function() {
+    return option(this.props, this.props.children);
+  }
+
+});
+
+module.exports = ReactDOMOption;
+
+}).call(this,require('_process'))
+},{"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58,"./warning":155,"_process":157}],50:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelect
+ */
+
+'use strict';
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+
+var select = ReactElement.createFactory('select');
+
+function updateOptionsIfPendingUpdateAndMounted() {
+  /*jshint validthis:true */
+  if (this._pendingUpdate) {
+    this._pendingUpdate = false;
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null && this.isMounted()) {
+      updateOptions(this, value);
+    }
+  }
+}
+
+/**
+ * Validation function for `value` and `defaultValue`.
+ * @private
+ */
+function selectValueType(props, propName, componentName) {
+  if (props[propName] == null) {
+    return null;
+  }
+  if (props.multiple) {
+    if (!Array.isArray(props[propName])) {
+      return new Error(
+        ("The `" + propName + "` prop supplied to <select> must be an array if ") +
+        ("`multiple` is true.")
+      );
+    }
+  } else {
+    if (Array.isArray(props[propName])) {
+      return new Error(
+        ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
+        ("value if `multiple` is false.")
+      );
+    }
+  }
+}
+
+/**
+ * @param {ReactComponent} component Instance of ReactDOMSelect
+ * @param {*} propValue A stringable (with `multiple`, a list of stringables).
+ * @private
+ */
+function updateOptions(component, propValue) {
+  var selectedValue, i, l;
+  var options = component.getDOMNode().options;
+
+  if (component.props.multiple) {
+    selectedValue = {};
+    for (i = 0, l = propValue.length; i < l; i++) {
+      selectedValue['' + propValue[i]] = true;
+    }
+    for (i = 0, l = options.length; i < l; i++) {
+      var selected = selectedValue.hasOwnProperty(options[i].value);
+      if (options[i].selected !== selected) {
+        options[i].selected = selected;
+      }
+    }
+  } else {
+    // Do not set `select.value` as exact behavior isn't consistent across all
+    // browsers for all cases.
+    selectedValue = '' + propValue;
+    for (i = 0, l = options.length; i < l; i++) {
+      if (options[i].value === selectedValue) {
+        options[i].selected = true;
+        return;
+      }
+    }
+    if (options.length) {
+      options[0].selected = true;
+    }
+  }
+}
+
+/**
+ * Implements a <select> native component that allows optionally setting the
+ * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
+ * stringable. If `multiple` is true, the prop must be an array of stringables.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that change the
+ * selected option will trigger updates to the rendered options.
+ *
+ * If it is supplied (and not null/undefined), the rendered options will not
+ * update in response to user actions. Instead, the `value` prop must change in
+ * order for the rendered options to update.
+ *
+ * If `defaultValue` is provided, any options with the supplied values will be
+ * selected.
+ */
+var ReactDOMSelect = ReactClass.createClass({
+  displayName: 'ReactDOMSelect',
+  tagName: 'SELECT',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  propTypes: {
+    defaultValue: selectValueType,
+    value: selectValueType
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    props.onChange = this._handleChange;
+    props.value = null;
+
+    return select(props, this.props.children);
+  },
+
+  componentWillMount: function() {
+    this._pendingUpdate = false;
+  },
+
+  componentDidMount: function() {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      updateOptions(this, value);
+    } else if (this.props.defaultValue != null) {
+      updateOptions(this, this.props.defaultValue);
+    }
+  },
+
+  componentDidUpdate: function(prevProps) {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      this._pendingUpdate = false;
+      updateOptions(this, value);
+    } else if (!prevProps.multiple !== !this.props.multiple) {
+      // For simplicity, reapply `defaultValue` if `multiple` is toggled.
+      if (this.props.defaultValue != null) {
+        updateOptions(this, this.props.defaultValue);
+      } else {
+        // Revert the select back to its default unselected state.
+        updateOptions(this, this.props.multiple ? [] : '');
+      }
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+
+    this._pendingUpdate = true;
+    ReactUpdates.asap(updateOptionsIfPendingUpdateAndMounted, this);
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMSelect;
+
+},{"./AutoFocusMixin":2,"./LinkedValueUtils":24,"./Object.assign":27,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58,"./ReactUpdates":88}],51:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMSelection
+ */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var getNodeForCharacterOffset = require("./getNodeForCharacterOffset");
+var getTextContentAccessor = require("./getTextContentAccessor");
+
+/**
+ * While `isCollapsed` is available on the Selection object and `collapsed`
+ * is available on the Range object, IE11 sometimes gets them wrong.
+ * If the anchor/focus nodes and offsets are the same, the range is collapsed.
+ */
+function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
+  return anchorNode === focusNode && anchorOffset === focusOffset;
+}
+
+/**
+ * Get the appropriate anchor and focus node/offset pairs for IE.
+ *
+ * The catch here is that IE's selection API doesn't provide information
+ * about whether the selection is forward or backward, so we have to
+ * behave as though it's always forward.
+ *
+ * IE text differs from modern selection in that it behaves as though
+ * block elements end with a new line. This means character offsets will
+ * differ between the two APIs.
+ *
+ * @param {DOMElement} node
+ * @return {object}
+ */
+function getIEOffsets(node) {
+  var selection = document.selection;
+  var selectedRange = selection.createRange();
+  var selectedLength = selectedRange.text.length;
+
+  // Duplicate selection so we can move range without breaking user selection.
+  var fromStart = selectedRange.duplicate();
+  fromStart.moveToElementText(node);
+  fromStart.setEndPoint('EndToStart', selectedRange);
+
+  var startOffset = fromStart.text.length;
+  var endOffset = startOffset + selectedLength;
+
+  return {
+    start: startOffset,
+    end: endOffset
+  };
+}
+
+/**
+ * @param {DOMElement} node
+ * @return {?object}
+ */
+function getModernOffsets(node) {
+  var selection = window.getSelection && window.getSelection();
+
+  if (!selection || selection.rangeCount === 0) {
+    return null;
+  }
+
+  var anchorNode = selection.anchorNode;
+  var anchorOffset = selection.anchorOffset;
+  var focusNode = selection.focusNode;
+  var focusOffset = selection.focusOffset;
+
+  var currentRange = selection.getRangeAt(0);
+
+  // If the node and offset values are the same, the selection is collapsed.
+  // `Selection.isCollapsed` is available natively, but IE sometimes gets
+  // this value wrong.
+  var isSelectionCollapsed = isCollapsed(
+    selection.anchorNode,
+    selection.anchorOffset,
+    selection.focusNode,
+    selection.focusOffset
+  );
+
+  var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;
+
+  var tempRange = currentRange.cloneRange();
+  tempRange.selectNodeContents(node);
+  tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);
+
+  var isTempRangeCollapsed = isCollapsed(
+    tempRange.startContainer,
+    tempRange.startOffset,
+    tempRange.endContainer,
+    tempRange.endOffset
+  );
+
+  var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
+  var end = start + rangeLength;
+
+  // Detect whether the selection is backward.
+  var detectionRange = document.createRange();
+  detectionRange.setStart(anchorNode, anchorOffset);
+  detectionRange.setEnd(focusNode, focusOffset);
+  var isBackward = detectionRange.collapsed;
+
+  return {
+    start: isBackward ? end : start,
+    end: isBackward ? start : end
+  };
+}
+
+/**
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setIEOffsets(node, offsets) {
+  var range = document.selection.createRange().duplicate();
+  var start, end;
+
+  if (typeof offsets.end === 'undefined') {
+    start = offsets.start;
+    end = start;
+  } else if (offsets.start > offsets.end) {
+    start = offsets.end;
+    end = offsets.start;
+  } else {
+    start = offsets.start;
+    end = offsets.end;
+  }
+
+  range.moveToElementText(node);
+  range.moveStart('character', start);
+  range.setEndPoint('EndToStart', range);
+  range.moveEnd('character', end - start);
+  range.select();
+}
+
+/**
+ * In modern non-IE browsers, we can support both forward and backward
+ * selections.
+ *
+ * Note: IE10+ supports the Selection object, but it does not support
+ * the `extend` method, which means that even in modern IE, it's not possible
+ * to programatically create a backward selection. Thus, for all IE
+ * versions, we use the old IE API to create our selections.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @param {object} offsets
+ */
+function setModernOffsets(node, offsets) {
+  if (!window.getSelection) {
+    return;
+  }
+
+  var selection = window.getSelection();
+  var length = node[getTextContentAccessor()].length;
+  var start = Math.min(offsets.start, length);
+  var end = typeof offsets.end === 'undefined' ?
+            start : Math.min(offsets.end, length);
+
+  // IE 11 uses modern selection, but doesn't support the extend method.
+  // Flip backward selections, so we can set with a single range.
+  if (!selection.extend && start > end) {
+    var temp = end;
+    end = start;
+    start = temp;
+  }
+
+  var startMarker = getNodeForCharacterOffset(node, start);
+  var endMarker = getNodeForCharacterOffset(node, end);
+
+  if (startMarker && endMarker) {
+    var range = document.createRange();
+    range.setStart(startMarker.node, startMarker.offset);
+    selection.removeAllRanges();
+
+    if (start > end) {
+      selection.addRange(range);
+      selection.extend(endMarker.node, endMarker.offset);
+    } else {
+      range.setEnd(endMarker.node, endMarker.offset);
+      selection.addRange(range);
+    }
+  }
+}
+
+var useIEOffsets = (
+  ExecutionEnvironment.canUseDOM &&
+  'selection' in document &&
+  !('getSelection' in window)
+);
+
+var ReactDOMSelection = {
+  /**
+   * @param {DOMElement} node
+   */
+  getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,
+
+  /**
+   * @param {DOMElement|DOMTextNode} node
+   * @param {object} offsets
+   */
+  setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
+};
+
+module.exports = ReactDOMSelection;
+
+},{"./ExecutionEnvironment":21,"./getNodeForCharacterOffset":129,"./getTextContentAccessor":131}],52:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMTextComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var ReactComponentBrowserEnvironment =
+  require("./ReactComponentBrowserEnvironment");
+var ReactDOMComponent = require("./ReactDOMComponent");
+
+var assign = require("./Object.assign");
+var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
+
+/**
+ * Text nodes violate a couple assumptions that React makes about components:
+ *
+ *  - When mounting text into the DOM, adjacent text nodes are merged.
+ *  - Text nodes cannot be assigned a React root ID.
+ *
+ * This component is used to wrap strings in elements so that they can undergo
+ * the same reconciliation that is applied to elements.
+ *
+ * TODO: Investigate representing React components in the DOM with text nodes.
+ *
+ * @class ReactDOMTextComponent
+ * @extends ReactComponent
+ * @internal
+ */
+var ReactDOMTextComponent = function(props) {
+  // This constructor and its argument is currently used by mocks.
+};
+
+assign(ReactDOMTextComponent.prototype, {
+
+  /**
+   * @param {ReactText} text
+   * @internal
+   */
+  construct: function(text) {
+    // TODO: This is really a ReactText (ReactNode), not a ReactElement
+    this._currentElement = text;
+    this._stringText = '' + text;
+
+    // Properties
+    this._rootNodeID = null;
+    this._mountIndex = 0;
+  },
+
+  /**
+   * Creates the markup for this text node. This node is not intended to have
+   * any features besides containing text content.
+   *
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {string} Markup for this text node.
+   * @internal
+   */
+  mountComponent: function(rootID, transaction, context) {
+    this._rootNodeID = rootID;
+    var escapedText = escapeTextContentForBrowser(this._stringText);
+
+    if (transaction.renderToStaticMarkup) {
+      // Normally we'd wrap this in a `span` for the reasons stated above, but
+      // since this is a situation where React won't take over (static pages),
+      // we can simply return the text as it is.
+      return escapedText;
+    }
+
+    return (
+      '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
+        escapedText +
+      '</span>'
+    );
+  },
+
+  /**
+   * Updates this component by updating the text content.
+   *
+   * @param {ReactText} nextText The next text content
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  receiveComponent: function(nextText, transaction) {
+    if (nextText !== this._currentElement) {
+      this._currentElement = nextText;
+      var nextStringText = '' + nextText;
+      if (nextStringText !== this._stringText) {
+        // TODO: Save this as pending props and use performUpdateIfNecessary
+        // and/or updateComponent to do the actual update for consistency with
+        // other component types?
+        this._stringText = nextStringText;
+        ReactDOMComponent.BackendIDOperations.updateTextContentByID(
+          this._rootNodeID,
+          nextStringText
+        );
+      }
+    }
+  },
+
+  unmountComponent: function() {
+    ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID);
+  }
+
+});
+
+module.exports = ReactDOMTextComponent;
+
+},{"./DOMPropertyOperations":11,"./Object.assign":27,"./ReactComponentBrowserEnvironment":36,"./ReactDOMComponent":43,"./escapeTextContentForBrowser":117}],53:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDOMTextarea
+ */
+
+'use strict';
+
+var AutoFocusMixin = require("./AutoFocusMixin");
+var DOMPropertyOperations = require("./DOMPropertyOperations");
+var LinkedValueUtils = require("./LinkedValueUtils");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+var warning = require("./warning");
+
+var textarea = ReactElement.createFactory('textarea');
+
+function forceUpdateIfMounted() {
+  /*jshint validthis:true */
+  if (this.isMounted()) {
+    this.forceUpdate();
+  }
+}
+
+/**
+ * Implements a <textarea> native component that allows setting `value`, and
+ * `defaultValue`. This differs from the traditional DOM API because value is
+ * usually set as PCDATA children.
+ *
+ * If `value` is not supplied (or null/undefined), user actions that affect the
+ * value will trigger updates to the element.
+ *
+ * If `value` is supplied (and not null/undefined), the rendered element will
+ * not trigger updates to the element. Instead, the `value` prop must change in
+ * order for the rendered element to be updated.
+ *
+ * The rendered element will be initialized with an empty value, the prop
+ * `defaultValue` if specified, or the children content (deprecated).
+ */
+var ReactDOMTextarea = ReactClass.createClass({
+  displayName: 'ReactDOMTextarea',
+  tagName: 'TEXTAREA',
+
+  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
+
+  getInitialState: function() {
+    var defaultValue = this.props.defaultValue;
+    // TODO (yungsters): Remove support for children content in <textarea>.
+    var children = this.props.children;
+    if (children != null) {
+      if ("production" !== process.env.NODE_ENV) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          false,
+          'Use the `defaultValue` or `value` props instead of setting ' +
+          'children on <textarea>.'
+        ) : null);
+      }
+      ("production" !== process.env.NODE_ENV ? invariant(
+        defaultValue == null,
+        'If you supply `defaultValue` on a <textarea>, do not pass children.'
+      ) : invariant(defaultValue == null));
+      if (Array.isArray(children)) {
+        ("production" !== process.env.NODE_ENV ? invariant(
+          children.length <= 1,
+          '<textarea> can only have at most one child.'
+        ) : invariant(children.length <= 1));
+        children = children[0];
+      }
+
+      defaultValue = '' + children;
+    }
+    if (defaultValue == null) {
+      defaultValue = '';
+    }
+    var value = LinkedValueUtils.getValue(this);
+    return {
+      // We save the initial value so that `ReactDOMComponent` doesn't update
+      // `textContent` (unnecessary since we update value).
+      // The initial value can be a boolean or object so that's why it's
+      // forced to be a string.
+      initialValue: '' + (value != null ? value : defaultValue)
+    };
+  },
+
+  render: function() {
+    // Clone `this.props` so we don't mutate the input.
+    var props = assign({}, this.props);
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      props.dangerouslySetInnerHTML == null,
+      '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
+    ) : invariant(props.dangerouslySetInnerHTML == null));
+
+    props.defaultValue = null;
+    props.value = null;
+    props.onChange = this._handleChange;
+
+    // Always set children to the same thing. In IE9, the selection range will
+    // get reset if `textContent` is mutated.
+    return textarea(props, this.state.initialValue);
+  },
+
+  componentDidUpdate: function(prevProps, prevState, prevContext) {
+    var value = LinkedValueUtils.getValue(this);
+    if (value != null) {
+      var rootNode = this.getDOMNode();
+      // Cast `value` to a string to ensure the value is set correctly. While
+      // browsers typically do this as necessary, jsdom doesn't.
+      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
+    }
+  },
+
+  _handleChange: function(event) {
+    var returnValue;
+    var onChange = LinkedValueUtils.getOnChange(this);
+    if (onChange) {
+      returnValue = onChange.call(this, event);
+    }
+    ReactUpdates.asap(forceUpdateIfMounted, this);
+    return returnValue;
+  }
+
+});
+
+module.exports = ReactDOMTextarea;
+
+}).call(this,require('_process'))
+},{"./AutoFocusMixin":2,"./DOMPropertyOperations":11,"./LinkedValueUtils":24,"./Object.assign":27,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactElement":58,"./ReactUpdates":88,"./invariant":136,"./warning":155,"_process":157}],54:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultBatchingStrategy
+ */
+
+'use strict';
+
+var ReactUpdates = require("./ReactUpdates");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+
+var RESET_BATCHED_UPDATES = {
+  initialize: emptyFunction,
+  close: function() {
+    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
+  }
+};
+
+var FLUSH_BATCHED_UPDATES = {
+  initialize: emptyFunction,
+  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
+};
+
+var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];
+
+function ReactDefaultBatchingStrategyTransaction() {
+  this.reinitializeTransaction();
+}
+
+assign(
+  ReactDefaultBatchingStrategyTransaction.prototype,
+  Transaction.Mixin,
+  {
+    getTransactionWrappers: function() {
+      return TRANSACTION_WRAPPERS;
+    }
+  }
+);
+
+var transaction = new ReactDefaultBatchingStrategyTransaction();
+
+var ReactDefaultBatchingStrategy = {
+  isBatchingUpdates: false,
+
+  /**
+   * Call the provided function in a context within which calls to `setState`
+   * and friends are batched such that components aren't updated unnecessarily.
+   */
+  batchedUpdates: function(callback, a, b, c, d) {
+    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;
+
+    ReactDefaultBatchingStrategy.isBatchingUpdates = true;
+
+    // The code is written this way to avoid extra allocations
+    if (alreadyBatchingUpdates) {
+      callback(a, b, c, d);
+    } else {
+      transaction.perform(callback, null, a, b, c, d);
+    }
+  }
+};
+
+module.exports = ReactDefaultBatchingStrategy;
+
+},{"./Object.assign":27,"./ReactUpdates":88,"./Transaction":104,"./emptyFunction":115}],55:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultInjection
+ */
+
+'use strict';
+
+var BeforeInputEventPlugin = require("./BeforeInputEventPlugin");
+var ChangeEventPlugin = require("./ChangeEventPlugin");
+var ClientReactRootIndex = require("./ClientReactRootIndex");
+var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
+var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var HTMLDOMPropertyConfig = require("./HTMLDOMPropertyConfig");
+var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin");
+var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
+var ReactClass = require("./ReactClass");
+var ReactComponentBrowserEnvironment =
+  require("./ReactComponentBrowserEnvironment");
+var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy");
+var ReactDOMComponent = require("./ReactDOMComponent");
+var ReactDOMButton = require("./ReactDOMButton");
+var ReactDOMForm = require("./ReactDOMForm");
+var ReactDOMImg = require("./ReactDOMImg");
+var ReactDOMIDOperations = require("./ReactDOMIDOperations");
+var ReactDOMIframe = require("./ReactDOMIframe");
+var ReactDOMInput = require("./ReactDOMInput");
+var ReactDOMOption = require("./ReactDOMOption");
+var ReactDOMSelect = require("./ReactDOMSelect");
+var ReactDOMTextarea = require("./ReactDOMTextarea");
+var ReactDOMTextComponent = require("./ReactDOMTextComponent");
+var ReactElement = require("./ReactElement");
+var ReactEventListener = require("./ReactEventListener");
+var ReactInjection = require("./ReactInjection");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMount = require("./ReactMount");
+var ReactReconcileTransaction = require("./ReactReconcileTransaction");
+var SelectEventPlugin = require("./SelectEventPlugin");
+var ServerReactRootIndex = require("./ServerReactRootIndex");
+var SimpleEventPlugin = require("./SimpleEventPlugin");
+var SVGDOMPropertyConfig = require("./SVGDOMPropertyConfig");
+
+var createFullPageComponent = require("./createFullPageComponent");
+
+function autoGenerateWrapperClass(type) {
+  return ReactClass.createClass({
+    tagName: type.toUpperCase(),
+    render: function() {
+      return new ReactElement(
+        type,
+        null,
+        null,
+        null,
+        null,
+        this.props
+      );
+    }
+  });
+}
+
+function inject() {
+  ReactInjection.EventEmitter.injectReactEventListener(
+    ReactEventListener
+  );
+
+  /**
+   * Inject modules for resolving DOM hierarchy and plugin ordering.
+   */
+  ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
+  ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
+  ReactInjection.EventPluginHub.injectMount(ReactMount);
+
+  /**
+   * Some important event plugins included by default (without having to require
+   * them).
+   */
+  ReactInjection.EventPluginHub.injectEventPluginsByName({
+    SimpleEventPlugin: SimpleEventPlugin,
+    EnterLeaveEventPlugin: EnterLeaveEventPlugin,
+    ChangeEventPlugin: ChangeEventPlugin,
+    MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
+    SelectEventPlugin: SelectEventPlugin,
+    BeforeInputEventPlugin: BeforeInputEventPlugin
+  });
+
+  ReactInjection.NativeComponent.injectGenericComponentClass(
+    ReactDOMComponent
+  );
+
+  ReactInjection.NativeComponent.injectTextComponentClass(
+    ReactDOMTextComponent
+  );
+
+  ReactInjection.NativeComponent.injectAutoWrapper(
+    autoGenerateWrapperClass
+  );
+
+  // This needs to happen before createFullPageComponent() otherwise the mixin
+  // won't be included.
+  ReactInjection.Class.injectMixin(ReactBrowserComponentMixin);
+
+  ReactInjection.NativeComponent.injectComponentClasses({
+    'button': ReactDOMButton,
+    'form': ReactDOMForm,
+    'iframe': ReactDOMIframe,
+    'img': ReactDOMImg,
+    'input': ReactDOMInput,
+    'option': ReactDOMOption,
+    'select': ReactDOMSelect,
+    'textarea': ReactDOMTextarea,
+
+    'html': createFullPageComponent('html'),
+    'head': createFullPageComponent('head'),
+    'body': createFullPageComponent('body')
+  });
+
+  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
+  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);
+
+  ReactInjection.EmptyComponent.injectEmptyComponent('noscript');
+
+  ReactInjection.Updates.injectReconcileTransaction(
+    ReactReconcileTransaction
+  );
+  ReactInjection.Updates.injectBatchingStrategy(
+    ReactDefaultBatchingStrategy
+  );
+
+  ReactInjection.RootIndex.injectCreateReactRootIndex(
+    ExecutionEnvironment.canUseDOM ?
+      ClientReactRootIndex.createReactRootIndex :
+      ServerReactRootIndex.createReactRootIndex
+  );
+
+  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
+  ReactInjection.DOMComponent.injectIDOperations(ReactDOMIDOperations);
+
+  if ("production" !== process.env.NODE_ENV) {
+    var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
+    if ((/[?&]react_perf\b/).test(url)) {
+      var ReactDefaultPerf = require("./ReactDefaultPerf");
+      ReactDefaultPerf.start();
+    }
+  }
+}
+
+module.exports = {
+  inject: inject
+};
+
+}).call(this,require('_process'))
+},{"./BeforeInputEventPlugin":3,"./ChangeEventPlugin":7,"./ClientReactRootIndex":8,"./DefaultEventPluginOrder":13,"./EnterLeaveEventPlugin":14,"./ExecutionEnvironment":21,"./HTMLDOMPropertyConfig":23,"./MobileSafariClickEventPlugin":26,"./ReactBrowserComponentMixin":30,"./ReactClass":34,"./ReactComponentBrowserEnvironment":36,"./ReactDOMButton":42,"./ReactDOMComponent":43,"./ReactDOMForm":44,"./ReactDOMIDOperations":45,"./ReactDOMIframe":46,"./ReactDOMImg":47,"./ReactDOMInput":48,"./Reac [...]
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerf
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
+var ReactMount = require("./ReactMount");
+var ReactPerf = require("./ReactPerf");
+
+var performanceNow = require("./performanceNow");
+
+function roundFloat(val) {
+  return Math.floor(val * 100) / 100;
+}
+
+function addValue(obj, key, val) {
+  obj[key] = (obj[key] || 0) + val;
+}
+
+var ReactDefaultPerf = {
+  _allMeasurements: [], // last item in the list is the current one
+  _mountStack: [0],
+  _injected: false,
+
+  start: function() {
+    if (!ReactDefaultPerf._injected) {
+      ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
+    }
+
+    ReactDefaultPerf._allMeasurements.length = 0;
+    ReactPerf.enableMeasure = true;
+  },
+
+  stop: function() {
+    ReactPerf.enableMeasure = false;
+  },
+
+  getLastMeasurements: function() {
+    return ReactDefaultPerf._allMeasurements;
+  },
+
+  printExclusive: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
+    console.table(summary.map(function(item) {
+      return {
+        'Component class name': item.componentName,
+        'Total inclusive time (ms)': roundFloat(item.inclusive),
+        'Exclusive mount time (ms)': roundFloat(item.exclusive),
+        'Exclusive render time (ms)': roundFloat(item.render),
+        'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
+        'Render time per instance (ms)': roundFloat(item.render / item.count),
+        'Instances': item.count
+      };
+    }));
+    // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
+    // number.
+  },
+
+  printInclusive: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
+    console.table(summary.map(function(item) {
+      return {
+        'Owner > component': item.componentName,
+        'Inclusive time (ms)': roundFloat(item.time),
+        'Instances': item.count
+      };
+    }));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  getMeasurementsSummaryMap: function(measurements) {
+    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
+      measurements,
+      true
+    );
+    return summary.map(function(item) {
+      return {
+        'Owner > component': item.componentName,
+        'Wasted time (ms)': item.time,
+        'Instances': item.count
+      };
+    });
+  },
+
+  printWasted: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  printDOM: function(measurements) {
+    measurements = measurements || ReactDefaultPerf._allMeasurements;
+    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
+    console.table(summary.map(function(item) {
+      var result = {};
+      result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
+      result['type'] = item.type;
+      result['args'] = JSON.stringify(item.args);
+      return result;
+    }));
+    console.log(
+      'Total time:',
+      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
+    );
+  },
+
+  _recordWrite: function(id, fnName, totalTime, args) {
+    // TODO: totalTime isn't that useful since it doesn't count paints/reflows
+    var writes =
+      ReactDefaultPerf
+        ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
+        .writes;
+    writes[id] = writes[id] || [];
+    writes[id].push({
+      type: fnName,
+      time: totalTime,
+      args: args
+    });
+  },
+
+  measure: function(moduleName, fnName, func) {
+    return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+      var totalTime;
+      var rv;
+      var start;
+
+      if (fnName === '_renderNewRootComponent' ||
+          fnName === 'flushBatchedUpdates') {
+        // A "measurement" is a set of metrics recorded for each flush. We want
+        // to group the metrics for a given flush together so we can look at the
+        // components that rendered and the DOM operations that actually
+        // happened to determine the amount of "wasted work" performed.
+        ReactDefaultPerf._allMeasurements.push({
+          exclusive: {},
+          inclusive: {},
+          render: {},
+          counts: {},
+          writes: {},
+          displayNames: {},
+          totalTime: 0
+        });
+        start = performanceNow();
+        rv = func.apply(this, args);
+        ReactDefaultPerf._allMeasurements[
+          ReactDefaultPerf._allMeasurements.length - 1
+        ].totalTime = performanceNow() - start;
+        return rv;
+      } else if (fnName === '_mountImageIntoNode' ||
+          moduleName === 'ReactDOMIDOperations') {
+        start = performanceNow();
+        rv = func.apply(this, args);
+        totalTime = performanceNow() - start;
+
+        if (fnName === '_mountImageIntoNode') {
+          var mountID = ReactMount.getID(args[1]);
+          ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
+        } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
+          // special format
+          args[0].forEach(function(update) {
+            var writeArgs = {};
+            if (update.fromIndex !== null) {
+              writeArgs.fromIndex = update.fromIndex;
+            }
+            if (update.toIndex !== null) {
+              writeArgs.toIndex = update.toIndex;
+            }
+            if (update.textContent !== null) {
+              writeArgs.textContent = update.textContent;
+            }
+            if (update.markupIndex !== null) {
+              writeArgs.markup = args[1][update.markupIndex];
+            }
+            ReactDefaultPerf._recordWrite(
+              update.parentID,
+              update.type,
+              totalTime,
+              writeArgs
+            );
+          });
+        } else {
+          // basic format
+          ReactDefaultPerf._recordWrite(
+            args[0],
+            fnName,
+            totalTime,
+            Array.prototype.slice.call(args, 1)
+          );
+        }
+        return rv;
+      } else if (moduleName === 'ReactCompositeComponent' && (
+        (// TODO: receiveComponent()?
+        (fnName === 'mountComponent' ||
+        fnName === 'updateComponent' || fnName === '_renderValidatedComponent')))) {
+
+        if (typeof this._currentElement.type === 'string') {
+          return func.apply(this, args);
+        }
+
+        var rootNodeID = fnName === 'mountComponent' ?
+          args[0] :
+          this._rootNodeID;
+        var isRender = fnName === '_renderValidatedComponent';
+        var isMount = fnName === 'mountComponent';
+
+        var mountStack = ReactDefaultPerf._mountStack;
+        var entry = ReactDefaultPerf._allMeasurements[
+          ReactDefaultPerf._allMeasurements.length - 1
+        ];
+
+        if (isRender) {
+          addValue(entry.counts, rootNodeID, 1);
+        } else if (isMount) {
+          mountStack.push(0);
+        }
+
+        start = performanceNow();
+        rv = func.apply(this, args);
+        totalTime = performanceNow() - start;
+
+        if (isRender) {
+          addValue(entry.render, rootNodeID, totalTime);
+        } else if (isMount) {
+          var subMountTime = mountStack.pop();
+          mountStack[mountStack.length - 1] += totalTime;
+          addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
+          addValue(entry.inclusive, rootNodeID, totalTime);
+        } else {
+          addValue(entry.inclusive, rootNodeID, totalTime);
+        }
+
+        entry.displayNames[rootNodeID] = {
+          current: this.getName(),
+          owner: this._currentElement._owner ?
+            this._currentElement._owner.getName() :
+            '<root>'
+        };
+
+        return rv;
+      } else {
+        return func.apply(this, args);
+      }
+    };
+  }
+};
+
+module.exports = ReactDefaultPerf;
+
+},{"./DOMProperty":10,"./ReactDefaultPerfAnalysis":57,"./ReactMount":71,"./ReactPerf":76,"./performanceNow":147}],57:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactDefaultPerfAnalysis
+ */
+
+var assign = require("./Object.assign");
+
+// Don't try to save users less than 1.2ms (a number I made up)
+var DONT_CARE_THRESHOLD = 1.2;
+var DOM_OPERATION_TYPES = {
+  '_mountImageIntoNode': 'set innerHTML',
+  INSERT_MARKUP: 'set innerHTML',
+  MOVE_EXISTING: 'move',
+  REMOVE_NODE: 'remove',
+  TEXT_CONTENT: 'set textContent',
+  'updatePropertyByID': 'update attribute',
+  'deletePropertyByID': 'delete attribute',
+  'updateStylesByID': 'update styles',
+  'updateInnerHTMLByID': 'set innerHTML',
+  'dangerouslyReplaceNodeWithMarkupByID': 'replace'
+};
+
+function getTotalTime(measurements) {
+  // TODO: return number of DOM ops? could be misleading.
+  // TODO: measure dropped frames after reconcile?
+  // TODO: log total time of each reconcile and the top-level component
+  // class that triggered it.
+  var totalTime = 0;
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    totalTime += measurement.totalTime;
+  }
+  return totalTime;
+}
+
+function getDOMSummary(measurements) {
+  var items = [];
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var id;
+
+    for (id in measurement.writes) {
+      measurement.writes[id].forEach(function(write) {
+        items.push({
+          id: id,
+          type: DOM_OPERATION_TYPES[write.type] || write.type,
+          args: write.args
+        });
+      });
+    }
+  }
+  return items;
+}
+
+function getExclusiveSummary(measurements) {
+  var candidates = {};
+  var displayName;
+
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var allIDs = assign(
+      {},
+      measurement.exclusive,
+      measurement.inclusive
+    );
+
+    for (var id in allIDs) {
+      displayName = measurement.displayNames[id].current;
+
+      candidates[displayName] = candidates[displayName] || {
+        componentName: displayName,
+        inclusive: 0,
+        exclusive: 0,
+        render: 0,
+        count: 0
+      };
+      if (measurement.render[id]) {
+        candidates[displayName].render += measurement.render[id];
+      }
+      if (measurement.exclusive[id]) {
+        candidates[displayName].exclusive += measurement.exclusive[id];
+      }
+      if (measurement.inclusive[id]) {
+        candidates[displayName].inclusive += measurement.inclusive[id];
+      }
+      if (measurement.counts[id]) {
+        candidates[displayName].count += measurement.counts[id];
+      }
+    }
+  }
+
+  // Now make a sorted array with the results.
+  var arr = [];
+  for (displayName in candidates) {
+    if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
+      arr.push(candidates[displayName]);
+    }
+  }
+
+  arr.sort(function(a, b) {
+    return b.exclusive - a.exclusive;
+  });
+
+  return arr;
+}
+
+function getInclusiveSummary(measurements, onlyClean) {
+  var candidates = {};
+  var inclusiveKey;
+
+  for (var i = 0; i < measurements.length; i++) {
+    var measurement = measurements[i];
+    var allIDs = assign(
+      {},
+      measurement.exclusive,
+      measurement.inclusive
+    );
+    var cleanComponents;
+
+    if (onlyClean) {
+      cleanComponents = getUnchangedComponents(measurement);
+    }
+
+    for (var id in allIDs) {
+      if (onlyClean && !cleanComponents[id]) {
+        continue;
+      }
+
+      var displayName = measurement.displayNames[id];
+
+      // Inclusive time is not useful for many components without knowing where
+      // they are instantiated. So we aggregate inclusive time with both the
+      // owner and current displayName as the key.
+      inclusiveKey = displayName.owner + ' > ' + displayName.current;
+
+      candidates[inclusiveKey] = candidates[inclusiveKey] || {
+        componentName: inclusiveKey,
+        time: 0,
+        count: 0
+      };
+
+      if (measurement.inclusive[id]) {
+        candidates[inclusiveKey].time += measurement.inclusive[id];
+      }
+      if (measurement.counts[id]) {
+        candidates[inclusiveKey].count += measurement.counts[id];
+      }
+    }
+  }
+
+  // Now make a sorted array with the results.
+  var arr = [];
+  for (inclusiveKey in candidates) {
+    if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
+      arr.push(candidates[inclusiveKey]);
+    }
+  }
+
+  arr.sort(function(a, b) {
+    return b.time - a.time;
+  });
+
+  return arr;
+}
+
+function getUnchangedComponents(measurement) {
+  // For a given reconcile, look at which components did not actually
+  // render anything to the DOM and return a mapping of their ID to
+  // the amount of time it took to render the entire subtree.
+  var cleanComponents = {};
+  var dirtyLeafIDs = Object.keys(measurement.writes);
+  var allIDs = assign({}, measurement.exclusive, measurement.inclusive);
+
+  for (var id in allIDs) {
+    var isDirty = false;
+    // For each component that rendered, see if a component that triggered
+    // a DOM op is in its subtree.
+    for (var i = 0; i < dirtyLeafIDs.length; i++) {
+      if (dirtyLeafIDs[i].indexOf(id) === 0) {
+        isDirty = true;
+        break;
+      }
+    }
+    if (!isDirty && measurement.counts[id] > 0) {
+      cleanComponents[id] = true;
+    }
+  }
+  return cleanComponents;
+}
+
+var ReactDefaultPerfAnalysis = {
+  getExclusiveSummary: getExclusiveSummary,
+  getInclusiveSummary: getInclusiveSummary,
+  getDOMSummary: getDOMSummary,
+  getTotalTime: getTotalTime
+};
+
+module.exports = ReactDefaultPerfAnalysis;
+
+},{"./Object.assign":27}],58:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElement
+ */
+
+'use strict';
+
+var ReactContext = require("./ReactContext");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+
+var assign = require("./Object.assign");
+var warning = require("./warning");
+
+var RESERVED_PROPS = {
+  key: true,
+  ref: true
+};
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} object
+ * @param {string} key
+ */
+function defineWarningProperty(object, key) {
+  Object.defineProperty(object, key, {
+
+    configurable: false,
+    enumerable: true,
+
+    get: function() {
+      if (!this._store) {
+        return null;
+      }
+      return this._store[key];
+    },
+
+    set: function(value) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        false,
+        'Don\'t set the %s property of the React element. Instead, ' +
+        'specify the correct value when initially creating the element.',
+        key
+      ) : null);
+      this._store[key] = value;
+    }
+
+  });
+}
+
+/**
+ * This is updated to true if the membrane is successfully created.
+ */
+var useMutationMembrane = false;
+
+/**
+ * Warn for mutations.
+ *
+ * @internal
+ * @param {object} element
+ */
+function defineMutationMembrane(prototype) {
+  try {
+    var pseudoFrozenProperties = {
+      props: true
+    };
+    for (var key in pseudoFrozenProperties) {
+      defineWarningProperty(prototype, key);
+    }
+    useMutationMembrane = true;
+  } catch (x) {
+    // IE will fail on defineProperty
+  }
+}
+
+/**
+ * Base constructor for all React elements. This is only used to make this
+ * work with a dynamic instanceof check. Nothing should live on this prototype.
+ *
+ * @param {*} type
+ * @param {string|object} ref
+ * @param {*} key
+ * @param {*} props
+ * @internal
+ */
+var ReactElement = function(type, key, ref, owner, context, props) {
+  // Built-in properties that belong on the element
+  this.type = type;
+  this.key = key;
+  this.ref = ref;
+
+  // Record the component responsible for creating this element.
+  this._owner = owner;
+
+  // TODO: Deprecate withContext, and then the context becomes accessible
+  // through the owner.
+  this._context = context;
+
+  if ("production" !== process.env.NODE_ENV) {
+    // The validation flag and props are currently mutative. We put them on
+    // an external backing store so that we can freeze the whole object.
+    // This can be replaced with a WeakMap once they are implemented in
+    // commonly used development environments.
+    this._store = {props: props, originalProps: assign({}, props)};
+
+    // To make comparing ReactElements easier for testing purposes, we make
+    // the validation flag non-enumerable (where possible, which should
+    // include every environment we run tests in), so the test framework
+    // ignores it.
+    try {
+      Object.defineProperty(this._store, 'validated', {
+        configurable: false,
+        enumerable: false,
+        writable: true
+      });
+    } catch (x) {
+    }
+    this._store.validated = false;
+
+    // We're not allowed to set props directly on the object so we early
+    // return and rely on the prototype membrane to forward to the backing
+    // store.
+    if (useMutationMembrane) {
+      Object.freeze(this);
+      return;
+    }
+  }
+
+  this.props = props;
+};
+
+// We intentionally don't expose the function on the constructor property.
+// ReactElement should be indistinguishable from a plain object.
+ReactElement.prototype = {
+  _isReactElement: true
+};
+
+if ("production" !== process.env.NODE_ENV) {
+  defineMutationMembrane(ReactElement.prototype);
+}
+
+ReactElement.createElement = function(type, config, children) {
+  var propName;
+
+  // Reserved names are extracted
+  var props = {};
+
+  var key = null;
+  var ref = null;
+
+  if (config != null) {
+    ref = config.ref === undefined ? null : config.ref;
+    key = config.key === undefined ? null : '' + config.key;
+    // Remaining properties are added to a new props object
+    for (propName in config) {
+      if (config.hasOwnProperty(propName) &&
+          !RESERVED_PROPS.hasOwnProperty(propName)) {
+        props[propName] = config[propName];
+      }
+    }
+  }
+
+  // Children can be more than one argument, and those are transferred onto
+  // the newly allocated props object.
+  var childrenLength = arguments.length - 2;
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = Array(childrenLength);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 2];
+    }
+    props.children = childArray;
+  }
+
+  // Resolve default props
+  if (type && type.defaultProps) {
+    var defaultProps = type.defaultProps;
+    for (propName in defaultProps) {
+      if (typeof props[propName] === 'undefined') {
+        props[propName] = defaultProps[propName];
+      }
+    }
+  }
+
+  return new ReactElement(
+    type,
+    key,
+    ref,
+    ReactCurrentOwner.current,
+    ReactContext.current,
+    props
+  );
+};
+
+ReactElement.createFactory = function(type) {
+  var factory = ReactElement.createElement.bind(null, type);
+  // Expose the type on the factory and the prototype so that it can be
+  // easily accessed on elements. E.g. <Foo />.type === Foo.type.
+  // This should not be named `constructor` since this may not be the function
+  // that created the element, and it may not even be a constructor.
+  // Legacy hook TODO: Warn if this is accessed
+  factory.type = type;
+  return factory;
+};
+
+ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
+  var newElement = new ReactElement(
+    oldElement.type,
+    oldElement.key,
+    oldElement.ref,
+    oldElement._owner,
+    oldElement._context,
+    newProps
+  );
+
+  if ("production" !== process.env.NODE_ENV) {
+    // If the key on the original is valid, then the clone is valid
+    newElement._store.validated = oldElement._store.validated;
+  }
+  return newElement;
+};
+
+ReactElement.cloneElement = function(element, config, children) {
+  var propName;
+
+  // Original props are copied
+  var props = assign({}, element.props);
+
+  // Reserved names are extracted
+  var key = element.key;
+  var ref = element.ref;
+
+  // Owner will be preserved, unless ref is overridden
+  var owner = element._owner;
+
+  if (config != null) {
+    if (config.ref !== undefined) {
+      // Silently steal the ref from the parent.
+      ref = config.ref;
+      owner = ReactCurrentOwner.current;
+    }
+    if (config.key !== undefined) {
+      key = '' + config.key;
+    }
+    // Remaining properties override existing props
+    for (propName in config) {
+      if (config.hasOwnProperty(propName) &&
+          !RESERVED_PROPS.hasOwnProperty(propName)) {
+        props[propName] = config[propName];
+      }
+    }
+  }
+
+  // Children can be more than one argument, and those are transferred onto
+  // the newly allocated props object.
+  var childrenLength = arguments.length - 2;
+  if (childrenLength === 1) {
+    props.children = children;
+  } else if (childrenLength > 1) {
+    var childArray = Array(childrenLength);
+    for (var i = 0; i < childrenLength; i++) {
+      childArray[i] = arguments[i + 2];
+    }
+    props.children = childArray;
+  }
+
+  return new ReactElement(
+    element.type,
+    key,
+    ref,
+    owner,
+    element._context,
+    props
+  );
+};
+
+/**
+ * @param {?object} object
+ * @return {boolean} True if `object` is a valid component.
+ * @final
+ */
+ReactElement.isValidElement = function(object) {
+  // ReactTestUtils is often used outside of beforeEach where as React is
+  // within it. This leads to two different instances of React on the same
+  // page. To identify a element from a different React instance we use
+  // a flag instead of an instanceof check.
+  var isElement = !!(object && object._isReactElement);
+  // if (isElement && !(object instanceof ReactElement)) {
+  // This is an indicator that you're using multiple versions of React at the
+  // same time. This will screw with ownership and stuff. Fix it, please.
+  // TODO: We could possibly warn here.
+  // }
+  return isElement;
+};
+
+module.exports = ReactElement;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./ReactContext":39,"./ReactCurrentOwner":40,"./warning":155,"_process":157}],59:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactElementValidator
+ */
+
+/**
+ * ReactElementValidator provides a wrapper around a element factory
+ * which validates the props passed to the element. This is intended to be
+ * used only in DEV and could be replaced by a static type checker for languages
+ * that support it.
+ */
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactFragment = require("./ReactFragment");
+var ReactPropTypeLocations = require("./ReactPropTypeLocations");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactNativeComponent = require("./ReactNativeComponent");
+
+var getIteratorFn = require("./getIteratorFn");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+function getDeclarationErrorAddendum() {
+  if (ReactCurrentOwner.current) {
+    var name = ReactCurrentOwner.current.getName();
+    if (name) {
+      return ' Check the render method of `' + name + '`.';
+    }
+  }
+  return '';
+}
+
+/**
+ * Warn if there's no key explicitly set on dynamic arrays of children or
+ * object keys are not valid. This allows us to keep track of children between
+ * updates.
+ */
+var ownerHasKeyUseWarning = {};
+
+var loggedTypeFailures = {};
+
+var NUMERIC_PROPERTY_REGEX = /^\d+$/;
+
+/**
+ * Gets the instance's name for use in warnings.
+ *
+ * @internal
+ * @return {?string} Display name or undefined
+ */
+function getName(instance) {
+  var publicInstance = instance && instance.getPublicInstance();
+  if (!publicInstance) {
+    return undefined;
+  }
+  var constructor = publicInstance.constructor;
+  if (!constructor) {
+    return undefined;
+  }
+  return constructor.displayName || constructor.name || undefined;
+}
+
+/**
+ * Gets the current owner's displayName for use in warnings.
+ *
+ * @internal
+ * @return {?string} Display name or undefined
+ */
+function getCurrentOwnerDisplayName() {
+  var current = ReactCurrentOwner.current;
+  return (
+    current && getName(current) || undefined
+  );
+}
+
+/**
+ * Warn if the element doesn't have an explicit key assigned to it.
+ * This element is in an array. The array could grow and shrink or be
+ * reordered. All children that haven't already been validated are required to
+ * have a "key" property assigned to it.
+ *
+ * @internal
+ * @param {ReactElement} element Element that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function validateExplicitKey(element, parentType) {
+  if (element._store.validated || element.key != null) {
+    return;
+  }
+  element._store.validated = true;
+
+  warnAndMonitorForKeyUse(
+    'Each child in an array or iterator should have a unique "key" prop.',
+    element,
+    parentType
+  );
+}
+
+/**
+ * Warn if the key is being defined as an object property but has an incorrect
+ * value.
+ *
+ * @internal
+ * @param {string} name Property name of the key.
+ * @param {ReactElement} element Component that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function validatePropertyKey(name, element, parentType) {
+  if (!NUMERIC_PROPERTY_REGEX.test(name)) {
+    return;
+  }
+  warnAndMonitorForKeyUse(
+    'Child objects should have non-numeric keys so ordering is preserved.',
+    element,
+    parentType
+  );
+}
+
+/**
+ * Shared warning and monitoring code for the key warnings.
+ *
+ * @internal
+ * @param {string} message The base warning that gets output.
+ * @param {ReactElement} element Component that requires a key.
+ * @param {*} parentType element's parent's type.
+ */
+function warnAndMonitorForKeyUse(message, element, parentType) {
+  var ownerName = getCurrentOwnerDisplayName();
+  var parentName = typeof parentType === 'string' ?
+    parentType : parentType.displayName || parentType.name;
+
+  var useName = ownerName || parentName;
+  var memoizer = ownerHasKeyUseWarning[message] || (
+    (ownerHasKeyUseWarning[message] = {})
+  );
+  if (memoizer.hasOwnProperty(useName)) {
+    return;
+  }
+  memoizer[useName] = true;
+
+  var parentOrOwnerAddendum =
+    ownerName ? (" Check the render method of " + ownerName + ".") :
+    parentName ? (" Check the React.render call using <" + parentName + ">.") :
+    '';
+
+  // Usually the current owner is the offender, but if it accepts children as a
+  // property, it may be the creator of the child that's responsible for
+  // assigning it a key.
+  var childOwnerAddendum = '';
+  if (element &&
+      element._owner &&
+      element._owner !== ReactCurrentOwner.current) {
+    // Name of the component that originally created this child.
+    var childOwnerName = getName(element._owner);
+
+    childOwnerAddendum = (" It was passed a child from " + childOwnerName + ".");
+  }
+
+  ("production" !== process.env.NODE_ENV ? warning(
+    false,
+    message + '%s%s See http://fb.me/react-warning-keys for more information.',
+    parentOrOwnerAddendum,
+    childOwnerAddendum
+  ) : null);
+}
+
+/**
+ * Ensure that every element either is passed in a static location, in an
+ * array with an explicit keys property defined, or in an object literal
+ * with valid key property.
+ *
+ * @internal
+ * @param {ReactNode} node Statically passed child of any type.
+ * @param {*} parentType node's parent's type.
+ */
+function validateChildKeys(node, parentType) {
+  if (Array.isArray(node)) {
+    for (var i = 0; i < node.length; i++) {
+      var child = node[i];
+      if (ReactElement.isValidElement(child)) {
+        validateExplicitKey(child, parentType);
+      }
+    }
+  } else if (ReactElement.isValidElement(node)) {
+    // This element was passed in a valid location.
+    node._store.validated = true;
+  } else if (node) {
+    var iteratorFn = getIteratorFn(node);
+    // Entry iterators provide implicit keys.
+    if (iteratorFn) {
+      if (iteratorFn !== node.entries) {
+        var iterator = iteratorFn.call(node);
+        var step;
+        while (!(step = iterator.next()).done) {
+          if (ReactElement.isValidElement(step.value)) {
+            validateExplicitKey(step.value, parentType);
+          }
+        }
+      }
+    } else if (typeof node === 'object') {
+      var fragment = ReactFragment.extractIfFragment(node);
+      for (var key in fragment) {
+        if (fragment.hasOwnProperty(key)) {
+          validatePropertyKey(key, fragment[key], parentType);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Assert that the props are valid
+ *
+ * @param {string} componentName Name of the component for error messages.
+ * @param {object} propTypes Map of prop name to a ReactPropType
+ * @param {object} props
+ * @param {string} location e.g. "prop", "context", "child context"
+ * @private
+ */
+function checkPropTypes(componentName, propTypes, props, location) {
+  for (var propName in propTypes) {
+    if (propTypes.hasOwnProperty(propName)) {
+      var error;
+      // Prop type validation may throw. In case they do, we don't want to
+      // fail the render phase where it didn't fail before. So we log it.
+      // After these have been cleaned up, we'll let them throw.
+      try {
+        // This is intentionally an invariant that gets caught. It's the same
+        // behavior as without this statement except with a better message.
+        ("production" !== process.env.NODE_ENV ? invariant(
+          typeof propTypes[propName] === 'function',
+          '%s: %s type `%s` is invalid; it must be a function, usually from ' +
+          'React.PropTypes.',
+          componentName || 'React class',
+          ReactPropTypeLocationNames[location],
+          propName
+        ) : invariant(typeof propTypes[propName] === 'function'));
+        error = propTypes[propName](props, propName, componentName, location);
+      } catch (ex) {
+        error = ex;
+      }
+      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
+        // Only monitor this failure once because there tends to be a lot of the
+        // same error.
+        loggedTypeFailures[error.message] = true;
+
+        var addendum = getDeclarationErrorAddendum(this);
+        ("production" !== process.env.NODE_ENV ? warning(false, 'Failed propType: %s%s', error.message, addendum) : null);
+      }
+    }
+  }
+}
+
+var warnedPropsMutations = {};
+
+/**
+ * Warn about mutating props when setting `propName` on `element`.
+ *
+ * @param {string} propName The string key within props that was set
+ * @param {ReactElement} element
+ */
+function warnForPropsMutation(propName, element) {
+  var type = element.type;
+  var elementName = typeof type === 'string' ? type : type.displayName;
+  var ownerName = element._owner ?
+    element._owner.getPublicInstance().constructor.displayName : null;
+
+  var warningKey = propName + '|' + elementName + '|' + ownerName;
+  if (warnedPropsMutations.hasOwnProperty(warningKey)) {
+    return;
+  }
+  warnedPropsMutations[warningKey] = true;
+
+  var elementInfo = '';
+  if (elementName) {
+    elementInfo = ' <' + elementName + ' />';
+  }
+  var ownerInfo = '';
+  if (ownerName) {
+    ownerInfo = ' The element was created by ' + ownerName + '.';
+  }
+
+  ("production" !== process.env.NODE_ENV ? warning(
+    false,
+    'Don\'t set .props.%s of the React component%s. ' +
+    'Instead, specify the correct value when ' +
+    'initially creating the element.%s',
+    propName,
+    elementInfo,
+    ownerInfo
+  ) : null);
+}
+
+// Inline Object.is polyfill
+function is(a, b) {
+  if (a !== a) {
+    // NaN
+    return b !== b;
+  }
+  if (a === 0 && b === 0) {
+    // +-0
+    return 1 / a === 1 / b;
+  }
+  return a === b;
+}
+
+/**
+ * Given an element, check if its props have been mutated since element
+ * creation (or the last call to this function). In particular, check if any
+ * new props have been added, which we can't directly catch by defining warning
+ * properties on the props object.
+ *
+ * @param {ReactElement} element
+ */
+function checkAndWarnForMutatedProps(element) {
+  if (!element._store) {
+    // Element was created using `new ReactElement` directly or with
+    // `ReactElement.createElement`; skip mutation checking
+    return;
+  }
+
+  var originalProps = element._store.originalProps;
+  var props = element.props;
+
+  for (var propName in props) {
+    if (props.hasOwnProperty(propName)) {
+      if (!originalProps.hasOwnProperty(propName) ||
+          !is(originalProps[propName], props[propName])) {
+        warnForPropsMutation(propName, element);
+
+        // Copy over the new value so that the two props objects match again
+        originalProps[propName] = props[propName];
+      }
+    }
+  }
+}
+
+/**
+ * Given an element, validate that its props follow the propTypes definition,
+ * provided by the type.
+ *
+ * @param {ReactElement} element
+ */
+function validatePropTypes(element) {
+  if (element.type == null) {
+    // This has already warned. Don't throw.
+    return;
+  }
+  // Extract the component class from the element. Converts string types
+  // to a composite class which may have propTypes.
+  // TODO: Validating a string's propTypes is not decoupled from the
+  // rendering target which is problematic.
+  var componentClass = ReactNativeComponent.getComponentClassForElement(
+    element
+  );
+  var name = componentClass.displayName || componentClass.name;
+  if (componentClass.propTypes) {
+    checkPropTypes(
+      name,
+      componentClass.propTypes,
+      element.props,
+      ReactPropTypeLocations.prop
+    );
+  }
+  if (typeof componentClass.getDefaultProps === 'function') {
+    ("production" !== process.env.NODE_ENV ? warning(
+      componentClass.getDefaultProps.isReactClassApproved,
+      'getDefaultProps is only used on classic React.createClass ' +
+      'definitions. Use a static property named `defaultProps` instead.'
+    ) : null);
+  }
+}
+
+var ReactElementValidator = {
+
+  checkAndWarnForMutatedProps: checkAndWarnForMutatedProps,
+
+  createElement: function(type, props, children) {
+    // We warn in this case but don't throw. We expect the element creation to
+    // succeed and there will likely be errors in render.
+    ("production" !== process.env.NODE_ENV ? warning(
+      type != null,
+      'React.createElement: type should not be null or undefined. It should ' +
+        'be a string (for DOM elements) or a ReactClass (for composite ' +
+        'components).'
+    ) : null);
+
+    var element = ReactElement.createElement.apply(this, arguments);
+
+    // The result can be nullish if a mock or a custom function is used.
+    // TODO: Drop this when these are no longer allowed as the type argument.
+    if (element == null) {
+      return element;
+    }
+
+    for (var i = 2; i < arguments.length; i++) {
+      validateChildKeys(arguments[i], type);
+    }
+
+    validatePropTypes(element);
+
+    return element;
+  },
+
+  createFactory: function(type) {
+    var validatedFactory = ReactElementValidator.createElement.bind(
+      null,
+      type
+    );
+    // Legacy hook TODO: Warn if this is accessed
+    validatedFactory.type = type;
+
+    if ("production" !== process.env.NODE_ENV) {
+      try {
+        Object.defineProperty(
+          validatedFactory,
+          'type',
+          {
+            enumerable: false,
+            get: function() {
+              ("production" !== process.env.NODE_ENV ? warning(
+                false,
+                'Factory.type is deprecated. Access the class directly ' +
+                'before passing it to createFactory.'
+              ) : null);
+              Object.defineProperty(this, 'type', {
+                value: type
+              });
+              return type;
+            }
+          }
+        );
+      } catch (x) {
+        // IE will fail on defineProperty (es5-shim/sham too)
+      }
+    }
+
+
+    return validatedFactory;
+  },
+
+  cloneElement: function(element, props, children) {
+    var newElement = ReactElement.cloneElement.apply(this, arguments);
+    for (var i = 2; i < arguments.length; i++) {
+      validateChildKeys(arguments[i], newElement.type);
+    }
+    validatePropTypes(newElement);
+    return newElement;
+  }
+
+};
+
+module.exports = ReactElementValidator;
+
+}).call(this,require('_process'))
+},{"./ReactCurrentOwner":40,"./ReactElement":58,"./ReactFragment":64,"./ReactNativeComponent":74,"./ReactPropTypeLocationNames":77,"./ReactPropTypeLocations":78,"./getIteratorFn":127,"./invariant":136,"./warning":155,"_process":157}],60:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEmptyComponent
+ */
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactInstanceMap = require("./ReactInstanceMap");
+
+var invariant = require("./invariant");
+
+var component;
+// This registry keeps track of the React IDs of the components that rendered to
+// `null` (in reality a placeholder such as `noscript`)
+var nullComponentIDsRegistry = {};
+
+var ReactEmptyComponentInjection = {
+  injectEmptyComponent: function(emptyComponent) {
+    component = ReactElement.createFactory(emptyComponent);
+  }
+};
+
+var ReactEmptyComponentType = function() {};
+ReactEmptyComponentType.prototype.componentDidMount = function() {
+  var internalInstance = ReactInstanceMap.get(this);
+  // TODO: Make sure we run these methods in the correct order, we shouldn't
+  // need this check. We're going to assume if we're here it means we ran
+  // componentWillUnmount already so there is no internal instance (it gets
+  // removed as part of the unmounting process).
+  if (!internalInstance) {
+    return;
+  }
+  registerNullComponentID(internalInstance._rootNodeID);
+};
+ReactEmptyComponentType.prototype.componentWillUnmount = function() {
+  var internalInstance = ReactInstanceMap.get(this);
+  // TODO: Get rid of this check. See TODO in componentDidMount.
+  if (!internalInstance) {
+    return;
+  }
+  deregisterNullComponentID(internalInstance._rootNodeID);
+};
+ReactEmptyComponentType.prototype.render = function() {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    component,
+    'Trying to return null from a render, but no null placeholder component ' +
+    'was injected.'
+  ) : invariant(component));
+  return component();
+};
+
+var emptyElement = ReactElement.createElement(ReactEmptyComponentType);
+
+/**
+ * Mark the component as having rendered to null.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function registerNullComponentID(id) {
+  nullComponentIDsRegistry[id] = true;
+}
+
+/**
+ * Unmark the component as having rendered to null: it renders to something now.
+ * @param {string} id Component's `_rootNodeID`.
+ */
+function deregisterNullComponentID(id) {
+  delete nullComponentIDsRegistry[id];
+}
+
+/**
+ * @param {string} id Component's `_rootNodeID`.
+ * @return {boolean} True if the component is rendered to null.
+ */
+function isNullComponentID(id) {
+  return !!nullComponentIDsRegistry[id];
+}
+
+var ReactEmptyComponent = {
+  emptyElement: emptyElement,
+  injection: ReactEmptyComponentInjection,
+  isNullComponentID: isNullComponentID
+};
+
+module.exports = ReactEmptyComponent;
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./ReactInstanceMap":68,"./invariant":136,"_process":157}],61:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactErrorUtils
+ * @typechecks
+ */
+
+"use strict";
+
+var ReactErrorUtils = {
+  /**
+   * Creates a guarded version of a function. This is supposed to make debugging
+   * of event handlers easier. To aid debugging with the browser's debugger,
+   * this currently simply returns the original function.
+   *
+   * @param {function} func Function to be executed
+   * @param {string} name The name of the guard
+   * @return {function}
+   */
+  guard: function(func, name) {
+    return func;
+  }
+};
+
+module.exports = ReactErrorUtils;
+
+},{}],62:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventEmitterMixin
+ */
+
+'use strict';
+
+var EventPluginHub = require("./EventPluginHub");
+
+function runEventQueueInBatch(events) {
+  EventPluginHub.enqueueEvents(events);
+  EventPluginHub.processEventQueue();
+}
+
+var ReactEventEmitterMixin = {
+
+  /**
+   * Streams a fired top-level event to `EventPluginHub` where plugins have the
+   * opportunity to create `ReactEvent`s to be dispatched.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {object} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native environment event.
+   */
+  handleTopLevel: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var events = EventPluginHub.extractEvents(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent
+    );
+
+    runEventQueueInBatch(events);
+  }
+};
+
+module.exports = ReactEventEmitterMixin;
+
+},{"./EventPluginHub":17}],63:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactEventListener
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var EventListener = require("./EventListener");
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var PooledClass = require("./PooledClass");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMount = require("./ReactMount");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var getEventTarget = require("./getEventTarget");
+var getUnboundedScrollPosition = require("./getUnboundedScrollPosition");
+
+/**
+ * Finds the parent React component of `node`.
+ *
+ * @param {*} node
+ * @return {?DOMEventTarget} Parent container, or `null` if the specified node
+ *                           is not nested.
+ */
+function findParent(node) {
+  // TODO: It may be a good idea to cache this to prevent unnecessary DOM
+  // traversal, but caching is difficult to do correctly without using a
+  // mutation observer to listen for all DOM changes.
+  var nodeID = ReactMount.getID(node);
+  var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
+  var container = ReactMount.findReactContainerForID(rootID);
+  var parent = ReactMount.getFirstReactDOM(container);
+  return parent;
+}
+
+// Used to store ancestor hierarchy in top level callback
+function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
+  this.topLevelType = topLevelType;
+  this.nativeEvent = nativeEvent;
+  this.ancestors = [];
+}
+assign(TopLevelCallbackBookKeeping.prototype, {
+  destructor: function() {
+    this.topLevelType = null;
+    this.nativeEvent = null;
+    this.ancestors.length = 0;
+  }
+});
+PooledClass.addPoolingTo(
+  TopLevelCallbackBookKeeping,
+  PooledClass.twoArgumentPooler
+);
+
+function handleTopLevelImpl(bookKeeping) {
+  var topLevelTarget = ReactMount.getFirstReactDOM(
+    getEventTarget(bookKeeping.nativeEvent)
+  ) || window;
+
+  // Loop through the hierarchy, in case there's any nested components.
+  // It's important that we build the array of ancestors before calling any
+  // event handlers, because event handlers can modify the DOM, leading to
+  // inconsistencies with ReactMount's node cache. See #1105.
+  var ancestor = topLevelTarget;
+  while (ancestor) {
+    bookKeeping.ancestors.push(ancestor);
+    ancestor = findParent(ancestor);
+  }
+
+  for (var i = 0, l = bookKeeping.ancestors.length; i < l; i++) {
+    topLevelTarget = bookKeeping.ancestors[i];
+    var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
+    ReactEventListener._handleTopLevel(
+      bookKeeping.topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      bookKeeping.nativeEvent
+    );
+  }
+}
+
+function scrollValueMonitor(cb) {
+  var scrollPosition = getUnboundedScrollPosition(window);
+  cb(scrollPosition);
+}
+
+var ReactEventListener = {
+  _enabled: true,
+  _handleTopLevel: null,
+
+  WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,
+
+  setHandleTopLevel: function(handleTopLevel) {
+    ReactEventListener._handleTopLevel = handleTopLevel;
+  },
+
+  setEnabled: function(enabled) {
+    ReactEventListener._enabled = !!enabled;
+  },
+
+  isEnabled: function() {
+    return ReactEventListener._enabled;
+  },
+
+
+  /**
+   * Traps top-level events by using event bubbling.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {string} handlerBaseName Event name (e.g. "click").
+   * @param {object} handle Element on which to attach listener.
+   * @return {object} An object with a remove function which will forcefully
+   *                  remove the listener.
+   * @internal
+   */
+  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
+    var element = handle;
+    if (!element) {
+      return null;
+    }
+    return EventListener.listen(
+      element,
+      handlerBaseName,
+      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+    );
+  },
+
+  /**
+   * Traps a top-level event by using event capturing.
+   *
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {string} handlerBaseName Event name (e.g. "click").
+   * @param {object} handle Element on which to attach listener.
+   * @return {object} An object with a remove function which will forcefully
+   *                  remove the listener.
+   * @internal
+   */
+  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
+    var element = handle;
+    if (!element) {
+      return null;
+    }
+    return EventListener.capture(
+      element,
+      handlerBaseName,
+      ReactEventListener.dispatchEvent.bind(null, topLevelType)
+    );
+  },
+
+  monitorScrollValue: function(refresh) {
+    var callback = scrollValueMonitor.bind(null, refresh);
+    EventListener.listen(window, 'scroll', callback);
+  },
+
+  dispatchEvent: function(topLevelType, nativeEvent) {
+    if (!ReactEventListener._enabled) {
+      return;
+    }
+
+    var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
+      topLevelType,
+      nativeEvent
+    );
+    try {
+      // Event queue being processed in the same cycle allows
+      // `preventDefault`.
+      ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
+    } finally {
+      TopLevelCallbackBookKeeping.release(bookKeeping);
+    }
+  }
+};
+
+module.exports = ReactEventListener;
+
+},{"./EventListener":16,"./ExecutionEnvironment":21,"./Object.assign":27,"./PooledClass":28,"./ReactInstanceHandles":67,"./ReactMount":71,"./ReactUpdates":88,"./getEventTarget":126,"./getUnboundedScrollPosition":132}],64:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+* @providesModule ReactFragment
+*/
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+
+var warning = require("./warning");
+
+/**
+ * We used to allow keyed objects to serve as a collection of ReactElements,
+ * or nested sets. This allowed us a way to explicitly key a set a fragment of
+ * components. This is now being replaced with an opaque data structure.
+ * The upgrade path is to call React.addons.createFragment({ key: value }) to
+ * create a keyed fragment. The resulting data structure is opaque, for now.
+ */
+
+if ("production" !== process.env.NODE_ENV) {
+  var fragmentKey = '_reactFragment';
+  var didWarnKey = '_reactDidWarn';
+  var canWarnForReactFragment = false;
+
+  try {
+    // Feature test. Don't even try to issue this warning if we can't use
+    // enumerable: false.
+
+    var dummy = function() {
+      return 1;
+    };
+
+    Object.defineProperty(
+      {},
+      fragmentKey,
+      {enumerable: false, value: true}
+    );
+
+    Object.defineProperty(
+      {},
+      'key',
+      {enumerable: true, get: dummy}
+    );
+
+    canWarnForReactFragment = true;
+  } catch (x) { }
+
+  var proxyPropertyAccessWithWarning = function(obj, key) {
+    Object.defineProperty(obj, key, {
+      enumerable: true,
+      get: function() {
+        ("production" !== process.env.NODE_ENV ? warning(
+          this[didWarnKey],
+          'A ReactFragment is an opaque type. Accessing any of its ' +
+          'properties is deprecated. Pass it to one of the React.Children ' +
+          'helpers.'
+        ) : null);
+        this[didWarnKey] = true;
+        return this[fragmentKey][key];
+      },
+      set: function(value) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          this[didWarnKey],
+          'A ReactFragment is an immutable opaque type. Mutating its ' +
+          'properties is deprecated.'
+        ) : null);
+        this[didWarnKey] = true;
+        this[fragmentKey][key] = value;
+      }
+    });
+  };
+
+  var issuedWarnings = {};
+
+  var didWarnForFragment = function(fragment) {
+    // We use the keys and the type of the value as a heuristic to dedupe the
+    // warning to avoid spamming too much.
+    var fragmentCacheKey = '';
+    for (var key in fragment) {
+      fragmentCacheKey += key + ':' + (typeof fragment[key]) + ',';
+    }
+    var alreadyWarnedOnce = !!issuedWarnings[fragmentCacheKey];
+    issuedWarnings[fragmentCacheKey] = true;
+    return alreadyWarnedOnce;
+  };
+}
+
+var ReactFragment = {
+  // Wrap a keyed object in an opaque proxy that warns you if you access any
+  // of its properties.
+  create: function(object) {
+    if ("production" !== process.env.NODE_ENV) {
+      if (typeof object !== 'object' || !object || Array.isArray(object)) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          false,
+          'React.addons.createFragment only accepts a single object.',
+          object
+        ) : null);
+        return object;
+      }
+      if (ReactElement.isValidElement(object)) {
+        ("production" !== process.env.NODE_ENV ? warning(
+          false,
+          'React.addons.createFragment does not accept a ReactElement ' +
+          'without a wrapper object.'
+        ) : null);
+        return object;
+      }
+      if (canWarnForReactFragment) {
+        var proxy = {};
+        Object.defineProperty(proxy, fragmentKey, {
+          enumerable: false,
+          value: object
+        });
+        Object.defineProperty(proxy, didWarnKey, {
+          writable: true,
+          enumerable: false,
+          value: false
+        });
+        for (var key in object) {
+          proxyPropertyAccessWithWarning(proxy, key);
+        }
+        Object.preventExtensions(proxy);
+        return proxy;
+      }
+    }
+    return object;
+  },
+  // Extract the original keyed object from the fragment opaque type. Warn if
+  // a plain object is passed here.
+  extract: function(fragment) {
+    if ("production" !== process.env.NODE_ENV) {
+      if (canWarnForReactFragment) {
+        if (!fragment[fragmentKey]) {
+          ("production" !== process.env.NODE_ENV ? warning(
+            didWarnForFragment(fragment),
+            'Any use of a keyed object should be wrapped in ' +
+            'React.addons.createFragment(object) before being passed as a ' +
+            'child.'
+          ) : null);
+          return fragment;
+        }
+        return fragment[fragmentKey];
+      }
+    }
+    return fragment;
+  },
+  // Check if this is a fragment and if so, extract the keyed object. If it
+  // is a fragment-like object, warn that it should be wrapped. Ignore if we
+  // can't determine what kind of object this is.
+  extractIfFragment: function(fragment) {
+    if ("production" !== process.env.NODE_ENV) {
+      if (canWarnForReactFragment) {
+        // If it is the opaque type, return the keyed object.
+        if (fragment[fragmentKey]) {
+          return fragment[fragmentKey];
+        }
+        // Otherwise, check each property if it has an element, if it does
+        // it is probably meant as a fragment, so we can warn early. Defer,
+        // the warning to extract.
+        for (var key in fragment) {
+          if (fragment.hasOwnProperty(key) &&
+              ReactElement.isValidElement(fragment[key])) {
+            // This looks like a fragment object, we should provide an
+            // early warning.
+            return ReactFragment.extract(fragment);
+          }
+        }
+      }
+    }
+    return fragment;
+  }
+};
+
+module.exports = ReactFragment;
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./warning":155,"_process":157}],65:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInjection
+ */
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+var EventPluginHub = require("./EventPluginHub");
+var ReactComponentEnvironment = require("./ReactComponentEnvironment");
+var ReactClass = require("./ReactClass");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactNativeComponent = require("./ReactNativeComponent");
+var ReactDOMComponent = require("./ReactDOMComponent");
+var ReactPerf = require("./ReactPerf");
+var ReactRootIndex = require("./ReactRootIndex");
+var ReactUpdates = require("./ReactUpdates");
+
+var ReactInjection = {
+  Component: ReactComponentEnvironment.injection,
+  Class: ReactClass.injection,
+  DOMComponent: ReactDOMComponent.injection,
+  DOMProperty: DOMProperty.injection,
+  EmptyComponent: ReactEmptyComponent.injection,
+  EventPluginHub: EventPluginHub.injection,
+  EventEmitter: ReactBrowserEventEmitter.injection,
+  NativeComponent: ReactNativeComponent.injection,
+  Perf: ReactPerf.injection,
+  RootIndex: ReactRootIndex.injection,
+  Updates: ReactUpdates.injection
+};
+
+module.exports = ReactInjection;
+
+},{"./DOMProperty":10,"./EventPluginHub":17,"./ReactBrowserEventEmitter":31,"./ReactClass":34,"./ReactComponentEnvironment":37,"./ReactDOMComponent":43,"./ReactEmptyComponent":60,"./ReactNativeComponent":74,"./ReactPerf":76,"./ReactRootIndex":84,"./ReactUpdates":88}],66:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInputSelection
+ */
+
+'use strict';
+
+var ReactDOMSelection = require("./ReactDOMSelection");
+
+var containsNode = require("./containsNode");
+var focusNode = require("./focusNode");
+var getActiveElement = require("./getActiveElement");
+
+function isInDocument(node) {
+  return containsNode(document.documentElement, node);
+}
+
+/**
+ * @ReactInputSelection: React input selection module. Based on Selection.js,
+ * but modified to be suitable for react and has a couple of bug fixes (doesn't
+ * assume buttons have range selections allowed).
+ * Input selection module for React.
+ */
+var ReactInputSelection = {
+
+  hasSelectionCapabilities: function(elem) {
+    return elem && (
+      ((elem.nodeName === 'INPUT' && elem.type === 'text') ||
+      elem.nodeName === 'TEXTAREA' || elem.contentEditable === 'true')
+    );
+  },
+
+  getSelectionInformation: function() {
+    var focusedElem = getActiveElement();
+    return {
+      focusedElem: focusedElem,
+      selectionRange:
+          ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
+          ReactInputSelection.getSelection(focusedElem) :
+          null
+    };
+  },
+
+  /**
+   * @restoreSelection: If any selection information was potentially lost,
+   * restore it. This is useful when performing operations that could remove dom
+   * nodes and place them back in, resulting in focus being lost.
+   */
+  restoreSelection: function(priorSelectionInformation) {
+    var curFocusedElem = getActiveElement();
+    var priorFocusedElem = priorSelectionInformation.focusedElem;
+    var priorSelectionRange = priorSelectionInformation.selectionRange;
+    if (curFocusedElem !== priorFocusedElem &&
+        isInDocument(priorFocusedElem)) {
+      if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
+        ReactInputSelection.setSelection(
+          priorFocusedElem,
+          priorSelectionRange
+        );
+      }
+      focusNode(priorFocusedElem);
+    }
+  },
+
+  /**
+   * @getSelection: Gets the selection bounds of a focused textarea, input or
+   * contentEditable node.
+   * - at input: Look up selection bounds of this input
+   * - at return {start: selectionStart, end: selectionEnd}
+   */
+  getSelection: function(input) {
+    var selection;
+
+    if ('selectionStart' in input) {
+      // Modern browser with input or textarea.
+      selection = {
+        start: input.selectionStart,
+        end: input.selectionEnd
+      };
+    } else if (document.selection && input.nodeName === 'INPUT') {
+      // IE8 input.
+      var range = document.selection.createRange();
+      // There can only be one selection per document in IE, so it must
+      // be in our element.
+      if (range.parentElement() === input) {
+        selection = {
+          start: -range.moveStart('character', -input.value.length),
+          end: -range.moveEnd('character', -input.value.length)
+        };
+      }
+    } else {
+      // Content editable or old IE textarea.
+      selection = ReactDOMSelection.getOffsets(input);
+    }
+
+    return selection || {start: 0, end: 0};
+  },
+
+  /**
+   * @setSelection: Sets the selection bounds of a textarea or input and focuses
+   * the input.
+   * - at input     Set selection bounds of this input or textarea
+   * - at offsets   Object of same form that is returned from get*
+   */
+  setSelection: function(input, offsets) {
+    var start = offsets.start;
+    var end = offsets.end;
+    if (typeof end === 'undefined') {
+      end = start;
+    }
+
+    if ('selectionStart' in input) {
+      input.selectionStart = start;
+      input.selectionEnd = Math.min(end, input.value.length);
+    } else if (document.selection && input.nodeName === 'INPUT') {
+      var range = input.createTextRange();
+      range.collapse(true);
+      range.moveStart('character', start);
+      range.moveEnd('character', end - start);
+      range.select();
+    } else {
+      ReactDOMSelection.setOffsets(input, offsets);
+    }
+  }
+};
+
+module.exports = ReactInputSelection;
+
+},{"./ReactDOMSelection":51,"./containsNode":110,"./focusNode":120,"./getActiveElement":122}],67:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInstanceHandles
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactRootIndex = require("./ReactRootIndex");
+
+var invariant = require("./invariant");
+
+var SEPARATOR = '.';
+var SEPARATOR_LENGTH = SEPARATOR.length;
+
+/**
+ * Maximum depth of traversals before we consider the possibility of a bad ID.
+ */
+var MAX_TREE_DEPTH = 100;
+
+/**
+ * Creates a DOM ID prefix to use when mounting React components.
+ *
+ * @param {number} index A unique integer
+ * @return {string} React root ID.
+ * @internal
+ */
+function getReactRootIDString(index) {
+  return SEPARATOR + index.toString(36);
+}
+
+/**
+ * Checks if a character in the supplied ID is a separator or the end.
+ *
+ * @param {string} id A React DOM ID.
+ * @param {number} index Index of the character to check.
+ * @return {boolean} True if the character is a separator or end of the ID.
+ * @private
+ */
+function isBoundary(id, index) {
+  return id.charAt(index) === SEPARATOR || index === id.length;
+}
+
+/**
+ * Checks if the supplied string is a valid React DOM ID.
+ *
+ * @param {string} id A React DOM ID, maybe.
+ * @return {boolean} True if the string is a valid React DOM ID.
+ * @private
+ */
+function isValidID(id) {
+  return id === '' || (
+    id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
+  );
+}
+
+/**
+ * Checks if the first ID is an ancestor of or equal to the second ID.
+ *
+ * @param {string} ancestorID
+ * @param {string} descendantID
+ * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
+ * @internal
+ */
+function isAncestorIDOf(ancestorID, descendantID) {
+  return (
+    descendantID.indexOf(ancestorID) === 0 &&
+    isBoundary(descendantID, ancestorID.length)
+  );
+}
+
+/**
+ * Gets the parent ID of the supplied React DOM ID, `id`.
+ *
+ * @param {string} id ID of a component.
+ * @return {string} ID of the parent, or an empty string.
+ * @private
+ */
+function getParentID(id) {
+  return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
+}
+
+/**
+ * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
+ * supplied `destinationID`. If they are equal, the ID is returned.
+ *
+ * @param {string} ancestorID ID of an ancestor node of `destinationID`.
+ * @param {string} destinationID ID of the destination node.
+ * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
+ * @private
+ */
+function getNextDescendantID(ancestorID, destinationID) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    isValidID(ancestorID) && isValidID(destinationID),
+    'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
+    ancestorID,
+    destinationID
+  ) : invariant(isValidID(ancestorID) && isValidID(destinationID)));
+  ("production" !== process.env.NODE_ENV ? invariant(
+    isAncestorIDOf(ancestorID, destinationID),
+    'getNextDescendantID(...): React has made an invalid assumption about ' +
+    'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
+    ancestorID,
+    destinationID
+  ) : invariant(isAncestorIDOf(ancestorID, destinationID)));
+  if (ancestorID === destinationID) {
+    return ancestorID;
+  }
+  // Skip over the ancestor and the immediate separator. Traverse until we hit
+  // another separator or we reach the end of `destinationID`.
+  var start = ancestorID.length + SEPARATOR_LENGTH;
+  var i;
+  for (i = start; i < destinationID.length; i++) {
+    if (isBoundary(destinationID, i)) {
+      break;
+    }
+  }
+  return destinationID.substr(0, i);
+}
+
+/**
+ * Gets the nearest common ancestor ID of two IDs.
+ *
+ * Using this ID scheme, the nearest common ancestor ID is the longest common
+ * prefix of the two IDs that immediately preceded a "marker" in both strings.
+ *
+ * @param {string} oneID
+ * @param {string} twoID
+ * @return {string} Nearest common ancestor ID, or the empty string if none.
+ * @private
+ */
+function getFirstCommonAncestorID(oneID, twoID) {
+  var minLength = Math.min(oneID.length, twoID.length);
+  if (minLength === 0) {
+    return '';
+  }
+  var lastCommonMarkerIndex = 0;
+  // Use `<=` to traverse until the "EOL" of the shorter string.
+  for (var i = 0; i <= minLength; i++) {
+    if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
+      lastCommonMarkerIndex = i;
+    } else if (oneID.charAt(i) !== twoID.charAt(i)) {
+      break;
+    }
+  }
+  var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
+  ("production" !== process.env.NODE_ENV ? invariant(
+    isValidID(longestCommonID),
+    'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
+    oneID,
+    twoID,
+    longestCommonID
+  ) : invariant(isValidID(longestCommonID)));
+  return longestCommonID;
+}
+
+/**
+ * Traverses the parent path between two IDs (either up or down). The IDs must
+ * not be the same, and there must exist a parent path between them. If the
+ * callback returns `false`, traversal is stopped.
+ *
+ * @param {?string} start ID at which to start traversal.
+ * @param {?string} stop ID at which to end traversal.
+ * @param {function} cb Callback to invoke each ID with.
+ * @param {?boolean} skipFirst Whether or not to skip the first node.
+ * @param {?boolean} skipLast Whether or not to skip the last node.
+ * @private
+ */
+function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
+  start = start || '';
+  stop = stop || '';
+  ("production" !== process.env.NODE_ENV ? invariant(
+    start !== stop,
+    'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
+    start
+  ) : invariant(start !== stop));
+  var traverseUp = isAncestorIDOf(stop, start);
+  ("production" !== process.env.NODE_ENV ? invariant(
+    traverseUp || isAncestorIDOf(start, stop),
+    'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
+    'not have a parent path.',
+    start,
+    stop
+  ) : invariant(traverseUp || isAncestorIDOf(start, stop)));
+  // Traverse from `start` to `stop` one depth at a time.
+  var depth = 0;
+  var traverse = traverseUp ? getParentID : getNextDescendantID;
+  for (var id = start; /* until break */; id = traverse(id, stop)) {
+    var ret;
+    if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
+      ret = cb(id, traverseUp, arg);
+    }
+    if (ret === false || id === stop) {
+      // Only break //after// visiting `stop`.
+      break;
+    }
+    ("production" !== process.env.NODE_ENV ? invariant(
+      depth++ < MAX_TREE_DEPTH,
+      'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
+      'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
+      start, stop
+    ) : invariant(depth++ < MAX_TREE_DEPTH));
+  }
+}
+
+/**
+ * Manages the IDs assigned to DOM representations of React components. This
+ * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
+ * order to simulate events).
+ *
+ * @internal
+ */
+var ReactInstanceHandles = {
+
+  /**
+   * Constructs a React root ID
+   * @return {string} A React root ID.
+   */
+  createReactRootID: function() {
+    return getReactRootIDString(ReactRootIndex.createReactRootIndex());
+  },
+
+  /**
+   * Constructs a React ID by joining a root ID with a name.
+   *
+   * @param {string} rootID Root ID of a parent component.
+   * @param {string} name A component's name (as flattened children).
+   * @return {string} A React ID.
+   * @internal
+   */
+  createReactID: function(rootID, name) {
+    return rootID + name;
+  },
+
+  /**
+   * Gets the DOM ID of the React component that is the root of the tree that
+   * contains the React component with the supplied DOM ID.
+   *
+   * @param {string} id DOM ID of a React component.
+   * @return {?string} DOM ID of the React component that is the root.
+   * @internal
+   */
+  getReactRootIDFromNodeID: function(id) {
+    if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
+      var index = id.indexOf(SEPARATOR, 1);
+      return index > -1 ? id.substr(0, index) : id;
+    }
+    return null;
+  },
+
+  /**
+   * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
+   * should would receive a `mouseEnter` or `mouseLeave` event.
+   *
+   * NOTE: Does not invoke the callback on the nearest common ancestor because
+   * nothing "entered" or "left" that element.
+   *
+   * @param {string} leaveID ID being left.
+   * @param {string} enterID ID being entered.
+   * @param {function} cb Callback to invoke on each entered/left ID.
+   * @param {*} upArg Argument to invoke the callback with on left IDs.
+   * @param {*} downArg Argument to invoke the callback with on entered IDs.
+   * @internal
+   */
+  traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
+    var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
+    if (ancestorID !== leaveID) {
+      traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
+    }
+    if (ancestorID !== enterID) {
+      traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
+    }
+  },
+
+  /**
+   * Simulates the traversal of a two-phase, capture/bubble event dispatch.
+   *
+   * NOTE: This traversal happens on IDs without touching the DOM.
+   *
+   * @param {string} targetID ID of the target node.
+   * @param {function} cb Callback to invoke.
+   * @param {*} arg Argument to invoke the callback with.
+   * @internal
+   */
+  traverseTwoPhase: function(targetID, cb, arg) {
+    if (targetID) {
+      traverseParentPath('', targetID, cb, arg, true, false);
+      traverseParentPath(targetID, '', cb, arg, false, true);
+    }
+  },
+
+  /**
+   * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
+   * example, passing `.0.$row-0.1` would result in `cb` getting called
+   * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
+   *
+   * NOTE: This traversal happens on IDs without touching the DOM.
+   *
+   * @param {string} targetID ID of the target node.
+   * @param {function} cb Callback to invoke.
+   * @param {*} arg Argument to invoke the callback with.
+   * @internal
+   */
+  traverseAncestors: function(targetID, cb, arg) {
+    traverseParentPath('', targetID, cb, arg, true, false);
+  },
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _getFirstCommonAncestorID: getFirstCommonAncestorID,
+
+  /**
+   * Exposed for unit testing.
+   * @private
+   */
+  _getNextDescendantID: getNextDescendantID,
+
+  isAncestorIDOf: isAncestorIDOf,
+
+  SEPARATOR: SEPARATOR
+
+};
+
+module.exports = ReactInstanceHandles;
+
+}).call(this,require('_process'))
+},{"./ReactRootIndex":84,"./invariant":136,"_process":157}],68:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactInstanceMap
+ */
+
+'use strict';
+
+/**
+ * `ReactInstanceMap` maintains a mapping from a public facing stateful
+ * instance (key) and the internal representation (value). This allows public
+ * methods to accept the user facing instance as an argument and map them back
+ * to internal methods.
+ */
+
+// TODO: Replace this with ES6: var ReactInstanceMap = new Map();
+var ReactInstanceMap = {
+
+  /**
+   * This API should be called `delete` but we'd have to make sure to always
+   * transform these to strings for IE support. When this transform is fully
+   * supported we can rename it.
+   */
+  remove: function(key) {
+    key._reactInternalInstance = undefined;
+  },
+
+  get: function(key) {
+    return key._reactInternalInstance;
+  },
+
+  has: function(key) {
+    return key._reactInternalInstance !== undefined;
+  },
+
+  set: function(key, value) {
+    key._reactInternalInstance = value;
+  }
+
+};
+
+module.exports = ReactInstanceMap;
+
+},{}],69:[function(require,module,exports){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactLifeCycle
+ */
+
+'use strict';
+
+/**
+ * This module manages the bookkeeping when a component is in the process
+ * of being mounted or being unmounted. This is used as a way to enforce
+ * invariants (or warnings) when it is not recommended to call
+ * setState/forceUpdate.
+ *
+ * currentlyMountingInstance: During the construction phase, it is not possible
+ * to trigger an update since the instance is not fully mounted yet. However, we
+ * currently allow this as a convenience for mutating the initial state.
+ *
+ * currentlyUnmountingInstance: During the unmounting phase, the instance is
+ * still mounted and can therefore schedule an update. However, this is not
+ * recommended and probably an error since it's about to be unmounted.
+ * Therefore we still want to trigger in an error for that case.
+ */
+
+var ReactLifeCycle = {
+  currentlyMountingInstance: null,
+  currentlyUnmountingInstance: null
+};
+
+module.exports = ReactLifeCycle;
+
+},{}],70:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMarkupChecksum
+ */
+
+'use strict';
+
+var adler32 = require("./adler32");
+
+var ReactMarkupChecksum = {
+  CHECKSUM_ATTR_NAME: 'data-react-checksum',
+
+  /**
+   * @param {string} markup Markup string
+   * @return {string} Markup string with checksum attribute attached
+   */
+  addChecksumToMarkup: function(markup) {
+    var checksum = adler32(markup);
+    return markup.replace(
+      '>',
+      ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
+    );
+  },
+
+  /**
+   * @param {string} markup to use
+   * @param {DOMElement} element root React element
+   * @returns {boolean} whether or not the markup is the same
+   */
+  canReuseMarkup: function(markup, element) {
+    var existingChecksum = element.getAttribute(
+      ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+    );
+    existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
+    var markupChecksum = adler32(markup);
+    return markupChecksum === existingChecksum;
+  }
+};
+
+module.exports = ReactMarkupChecksum;
+
+},{"./adler32":107}],71:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMount
+ */
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactElementValidator = require("./ReactElementValidator");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactInstanceMap = require("./ReactInstanceMap");
+var ReactMarkupChecksum = require("./ReactMarkupChecksum");
+var ReactPerf = require("./ReactPerf");
+var ReactReconciler = require("./ReactReconciler");
+var ReactUpdateQueue = require("./ReactUpdateQueue");
+var ReactUpdates = require("./ReactUpdates");
+
+var emptyObject = require("./emptyObject");
+var containsNode = require("./containsNode");
+var getReactRootElementInContainer = require("./getReactRootElementInContainer");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var invariant = require("./invariant");
+var setInnerHTML = require("./setInnerHTML");
+var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
+var warning = require("./warning");
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+
+var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
+var nodeCache = {};
+
+var ELEMENT_NODE_TYPE = 1;
+var DOC_NODE_TYPE = 9;
+
+/** Mapping from reactRootID to React component instance. */
+var instancesByReactRootID = {};
+
+/** Mapping from reactRootID to `container` nodes. */
+var containersByReactRootID = {};
+
+if ("production" !== process.env.NODE_ENV) {
+  /** __DEV__-only mapping from reactRootID to root elements. */
+  var rootElementsByReactRootID = {};
+}
+
+// Used to store breadth-first search state in findComponentRoot.
+var findComponentRootReusableArray = [];
+
+/**
+ * Finds the index of the first character
+ * that's not common between the two given strings.
+ *
+ * @return {number} the index of the character where the strings diverge
+ */
+function firstDifferenceIndex(string1, string2) {
+  var minLen = Math.min(string1.length, string2.length);
+  for (var i = 0; i < minLen; i++) {
+    if (string1.charAt(i) !== string2.charAt(i)) {
+      return i;
+    }
+  }
+  return string1.length === string2.length ? -1 : minLen;
+}
+
+/**
+ * @param {DOMElement} container DOM element that may contain a React component.
+ * @return {?string} A "reactRoot" ID, if a React component is rendered.
+ */
+function getReactRootID(container) {
+  var rootElement = getReactRootElementInContainer(container);
+  return rootElement && ReactMount.getID(rootElement);
+}
+
+/**
+ * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
+ * element can return its control whose name or ID equals ATTR_NAME. All
+ * DOM nodes support `getAttributeNode` but this can also get called on
+ * other objects so just return '' if we're given something other than a
+ * DOM node (such as window).
+ *
+ * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
+ * @return {string} ID of the supplied `domNode`.
+ */
+function getID(node) {
+  var id = internalGetID(node);
+  if (id) {
+    if (nodeCache.hasOwnProperty(id)) {
+      var cached = nodeCache[id];
+      if (cached !== node) {
+        ("production" !== process.env.NODE_ENV ? invariant(
+          !isValid(cached, id),
+          'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
+          ATTR_NAME, id
+        ) : invariant(!isValid(cached, id)));
+
+        nodeCache[id] = node;
+      }
+    } else {
+      nodeCache[id] = node;
+    }
+  }
+
+  return id;
+}
+
+function internalGetID(node) {
+  // If node is something like a window, document, or text node, none of
+  // which support attributes or a .getAttribute method, gracefully return
+  // the empty string, as if the attribute were missing.
+  return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
+}
+
+/**
+ * Sets the React-specific ID of the given node.
+ *
+ * @param {DOMElement} node The DOM node whose ID will be set.
+ * @param {string} id The value of the ID attribute.
+ */
+function setID(node, id) {
+  var oldID = internalGetID(node);
+  if (oldID !== id) {
+    delete nodeCache[oldID];
+  }
+  node.setAttribute(ATTR_NAME, id);
+  nodeCache[id] = node;
+}
+
+/**
+ * Finds the node with the supplied React-generated DOM ID.
+ *
+ * @param {string} id A React-generated DOM ID.
+ * @return {DOMElement} DOM node with the suppled `id`.
+ * @internal
+ */
+function getNode(id) {
+  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
+    nodeCache[id] = ReactMount.findReactNodeByID(id);
+  }
+  return nodeCache[id];
+}
+
+/**
+ * Finds the node with the supplied public React instance.
+ *
+ * @param {*} instance A public React instance.
+ * @return {?DOMElement} DOM node with the suppled `id`.
+ * @internal
+ */
+function getNodeFromInstance(instance) {
+  var id = ReactInstanceMap.get(instance)._rootNodeID;
+  if (ReactEmptyComponent.isNullComponentID(id)) {
+    return null;
+  }
+  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
+    nodeCache[id] = ReactMount.findReactNodeByID(id);
+  }
+  return nodeCache[id];
+}
+
+/**
+ * A node is "valid" if it is contained by a currently mounted container.
+ *
+ * This means that the node does not have to be contained by a document in
+ * order to be considered valid.
+ *
+ * @param {?DOMElement} node The candidate DOM node.
+ * @param {string} id The expected ID of the node.
+ * @return {boolean} Whether the node is contained by a mounted container.
+ */
+function isValid(node, id) {
+  if (node) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      internalGetID(node) === id,
+      'ReactMount: Unexpected modification of `%s`',
+      ATTR_NAME
+    ) : invariant(internalGetID(node) === id));
+
+    var container = ReactMount.findReactContainerForID(id);
+    if (container && containsNode(container, node)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * Causes the cache to forget about one React-specific ID.
+ *
+ * @param {string} id The ID to forget.
+ */
+function purgeID(id) {
+  delete nodeCache[id];
+}
+
+var deepestNodeSoFar = null;
+function findDeepestCachedAncestorImpl(ancestorID) {
+  var ancestor = nodeCache[ancestorID];
+  if (ancestor && isValid(ancestor, ancestorID)) {
+    deepestNodeSoFar = ancestor;
+  } else {
+    // This node isn't populated in the cache, so presumably none of its
+    // descendants are. Break out of the loop.
+    return false;
+  }
+}
+
+/**
+ * Return the deepest cached node whose ID is a prefix of `targetID`.
+ */
+function findDeepestCachedAncestor(targetID) {
+  deepestNodeSoFar = null;
+  ReactInstanceHandles.traverseAncestors(
+    targetID,
+    findDeepestCachedAncestorImpl
+  );
+
+  var foundNode = deepestNodeSoFar;
+  deepestNodeSoFar = null;
+  return foundNode;
+}
+
+/**
+ * Mounts this component and inserts it into the DOM.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {ReactReconcileTransaction} transaction
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ */
+function mountComponentIntoNode(
+    componentInstance,
+    rootID,
+    container,
+    transaction,
+    shouldReuseMarkup) {
+  var markup = ReactReconciler.mountComponent(
+    componentInstance, rootID, transaction, emptyObject
+  );
+  componentInstance._isTopLevel = true;
+  ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup);
+}
+
+/**
+ * Batched mount.
+ *
+ * @param {ReactComponent} componentInstance The instance to mount.
+ * @param {string} rootID DOM ID of the root node.
+ * @param {DOMElement} container DOM element to mount into.
+ * @param {boolean} shouldReuseMarkup If true, do not insert markup
+ */
+function batchedMountComponentIntoNode(
+    componentInstance,
+    rootID,
+    container,
+    shouldReuseMarkup) {
+  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
+  transaction.perform(
+    mountComponentIntoNode,
+    null,
+    componentInstance,
+    rootID,
+    container,
+    transaction,
+    shouldReuseMarkup
+  );
+  ReactUpdates.ReactReconcileTransaction.release(transaction);
+}
+
+/**
+ * Mounting is the process of initializing a React component by creating its
+ * representative DOM elements and inserting them into a supplied `container`.
+ * Any prior content inside `container` is destroyed in the process.
+ *
+ *   ReactMount.render(
+ *     component,
+ *     document.getElementById('container')
+ *   );
+ *
+ *   <div id="container">                   <-- Supplied `container`.
+ *     <div data-reactid=".3">              <-- Rendered reactRoot of React
+ *       // ...                                 component.
+ *     </div>
+ *   </div>
+ *
+ * Inside of `container`, the first element rendered is the "reactRoot".
+ */
+var ReactMount = {
+  /** Exposed for debugging purposes **/
+  _instancesByReactRootID: instancesByReactRootID,
+
+  /**
+   * This is a hook provided to support rendering React components while
+   * ensuring that the apparent scroll position of its `container` does not
+   * change.
+   *
+   * @param {DOMElement} container The `container` being rendered into.
+   * @param {function} renderCallback This must be called once to do the render.
+   */
+  scrollMonitor: function(container, renderCallback) {
+    renderCallback();
+  },
+
+  /**
+   * Take a component that's already mounted into the DOM and replace its props
+   * @param {ReactComponent} prevComponent component instance already in the DOM
+   * @param {ReactElement} nextElement component instance to render
+   * @param {DOMElement} container container to render into
+   * @param {?function} callback function triggered on completion
+   */
+  _updateRootComponent: function(
+      prevComponent,
+      nextElement,
+      container,
+      callback) {
+    if ("production" !== process.env.NODE_ENV) {
+      ReactElementValidator.checkAndWarnForMutatedProps(nextElement);
+    }
+
+    ReactMount.scrollMonitor(container, function() {
+      ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement);
+      if (callback) {
+        ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
+      }
+    });
+
+    if ("production" !== process.env.NODE_ENV) {
+      // Record the root element in case it later gets transplanted.
+      rootElementsByReactRootID[getReactRootID(container)] =
+        getReactRootElementInContainer(container);
+    }
+
+    return prevComponent;
+  },
+
+  /**
+   * Register a component into the instance map and starts scroll value
+   * monitoring
+   * @param {ReactComponent} nextComponent component instance to render
+   * @param {DOMElement} container container to render into
+   * @return {string} reactRoot ID prefix
+   */
+  _registerComponent: function(nextComponent, container) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      '_registerComponent(...): Target container is not a DOM element.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    ReactBrowserEventEmitter.ensureScrollValueMonitoring();
+
+    var reactRootID = ReactMount.registerContainer(container);
+    instancesByReactRootID[reactRootID] = nextComponent;
+    return reactRootID;
+  },
+
+  /**
+   * Render a new component into the DOM.
+   * @param {ReactElement} nextElement element to render
+   * @param {DOMElement} container container to render into
+   * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
+   * @return {ReactComponent} nextComponent
+   */
+  _renderNewRootComponent: function(
+    nextElement,
+    container,
+    shouldReuseMarkup
+  ) {
+    // Various parts of our code (such as ReactCompositeComponent's
+    // _renderValidatedComponent) assume that calls to render aren't nested;
+    // verify that that's the case.
+    ("production" !== process.env.NODE_ENV ? warning(
+      ReactCurrentOwner.current == null,
+      '_renderNewRootComponent(): Render methods should be a pure function ' +
+      'of props and state; triggering nested component updates from ' +
+      'render is not allowed. If necessary, trigger nested updates in ' +
+      'componentDidUpdate.'
+    ) : null);
+
+    var componentInstance = instantiateReactComponent(nextElement, null);
+    var reactRootID = ReactMount._registerComponent(
+      componentInstance,
+      container
+    );
+
+    // The initial render is synchronous but any updates that happen during
+    // rendering, in componentWillMount or componentDidMount, will be batched
+    // according to the current batching strategy.
+
+    ReactUpdates.batchedUpdates(
+      batchedMountComponentIntoNode,
+      componentInstance,
+      reactRootID,
+      container,
+      shouldReuseMarkup
+    );
+
+    if ("production" !== process.env.NODE_ENV) {
+      // Record the root element in case it later gets transplanted.
+      rootElementsByReactRootID[reactRootID] =
+        getReactRootElementInContainer(container);
+    }
+
+    return componentInstance;
+  },
+
+  /**
+   * Renders a React component into the DOM in the supplied `container`.
+   *
+   * If the React component was previously rendered into `container`, this will
+   * perform an update on it and only mutate the DOM as necessary to reflect the
+   * latest React component.
+   *
+   * @param {ReactElement} nextElement Component element to render.
+   * @param {DOMElement} container DOM element to render into.
+   * @param {?function} callback function triggered on completion
+   * @return {ReactComponent} Component instance rendered in `container`.
+   */
+  render: function(nextElement, container, callback) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ReactElement.isValidElement(nextElement),
+      'React.render(): Invalid component element.%s',
+      (
+        typeof nextElement === 'string' ?
+          ' Instead of passing an element string, make sure to instantiate ' +
+          'it by passing it to React.createElement.' :
+        typeof nextElement === 'function' ?
+          ' Instead of passing a component class, make sure to instantiate ' +
+          'it by passing it to React.createElement.' :
+        // Check if it quacks like an element
+        nextElement != null && nextElement.props !== undefined ?
+          ' This may be caused by unintentionally loading two independent ' +
+          'copies of React.' :
+          ''
+      )
+    ) : invariant(ReactElement.isValidElement(nextElement)));
+
+    var prevComponent = instancesByReactRootID[getReactRootID(container)];
+
+    if (prevComponent) {
+      var prevElement = prevComponent._currentElement;
+      if (shouldUpdateReactComponent(prevElement, nextElement)) {
+        return ReactMount._updateRootComponent(
+          prevComponent,
+          nextElement,
+          container,
+          callback
+        ).getPublicInstance();
+      } else {
+        ReactMount.unmountComponentAtNode(container);
+      }
+    }
+
+    var reactRootElement = getReactRootElementInContainer(container);
+    var containerHasReactMarkup =
+      reactRootElement && ReactMount.isRenderedByReact(reactRootElement);
+
+    if ("production" !== process.env.NODE_ENV) {
+      if (!containerHasReactMarkup || reactRootElement.nextSibling) {
+        var rootElementSibling = reactRootElement;
+        while (rootElementSibling) {
+          if (ReactMount.isRenderedByReact(rootElementSibling)) {
+            ("production" !== process.env.NODE_ENV ? warning(
+              false,
+              'render(): Target node has markup rendered by React, but there ' +
+              'are unrelated nodes as well. This is most commonly caused by ' +
+              'white-space inserted around server-rendered markup.'
+            ) : null);
+            break;
+          }
+
+          rootElementSibling = rootElementSibling.nextSibling;
+        }
+      }
+    }
+
+    var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;
+
+    var component = ReactMount._renderNewRootComponent(
+      nextElement,
+      container,
+      shouldReuseMarkup
+    ).getPublicInstance();
+    if (callback) {
+      callback.call(component);
+    }
+    return component;
+  },
+
+  /**
+   * Constructs a component instance of `constructor` with `initialProps` and
+   * renders it into the supplied `container`.
+   *
+   * @param {function} constructor React component constructor.
+   * @param {?object} props Initial props of the component instance.
+   * @param {DOMElement} container DOM element to render into.
+   * @return {ReactComponent} Component instance rendered in `container`.
+   */
+  constructAndRenderComponent: function(constructor, props, container) {
+    var element = ReactElement.createElement(constructor, props);
+    return ReactMount.render(element, container);
+  },
+
+  /**
+   * Constructs a component instance of `constructor` with `initialProps` and
+   * renders it into a container node identified by supplied `id`.
+   *
+   * @param {function} componentConstructor React component constructor
+   * @param {?object} props Initial props of the component instance.
+   * @param {string} id ID of the DOM element to render into.
+   * @return {ReactComponent} Component instance rendered in the container node.
+   */
+  constructAndRenderComponentByID: function(constructor, props, id) {
+    var domNode = document.getElementById(id);
+    ("production" !== process.env.NODE_ENV ? invariant(
+      domNode,
+      'Tried to get element with id of "%s" but it is not present on the page.',
+      id
+    ) : invariant(domNode));
+    return ReactMount.constructAndRenderComponent(constructor, props, domNode);
+  },
+
+  /**
+   * Registers a container node into which React components will be rendered.
+   * This also creates the "reactRoot" ID that will be assigned to the element
+   * rendered within.
+   *
+   * @param {DOMElement} container DOM element to register as a container.
+   * @return {string} The "reactRoot" ID of elements rendered within.
+   */
+  registerContainer: function(container) {
+    var reactRootID = getReactRootID(container);
+    if (reactRootID) {
+      // If one exists, make sure it is a valid "reactRoot" ID.
+      reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
+    }
+    if (!reactRootID) {
+      // No valid "reactRoot" ID found, create one.
+      reactRootID = ReactInstanceHandles.createReactRootID();
+    }
+    containersByReactRootID[reactRootID] = container;
+    return reactRootID;
+  },
+
+  /**
+   * Unmounts and destroys the React component rendered in the `container`.
+   *
+   * @param {DOMElement} container DOM element containing a React component.
+   * @return {boolean} True if a component was found in and unmounted from
+   *                   `container`
+   */
+  unmountComponentAtNode: function(container) {
+    // Various parts of our code (such as ReactCompositeComponent's
+    // _renderValidatedComponent) assume that calls to render aren't nested;
+    // verify that that's the case. (Strictly speaking, unmounting won't cause a
+    // render but we still don't expect to be in a render call here.)
+    ("production" !== process.env.NODE_ENV ? warning(
+      ReactCurrentOwner.current == null,
+      'unmountComponentAtNode(): Render methods should be a pure function of ' +
+      'props and state; triggering nested component updates from render is ' +
+      'not allowed. If necessary, trigger nested updates in ' +
+      'componentDidUpdate.'
+    ) : null);
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      'unmountComponentAtNode(...): Target container is not a DOM element.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    var reactRootID = getReactRootID(container);
+    var component = instancesByReactRootID[reactRootID];
+    if (!component) {
+      return false;
+    }
+    ReactMount.unmountComponentFromNode(component, container);
+    delete instancesByReactRootID[reactRootID];
+    delete containersByReactRootID[reactRootID];
+    if ("production" !== process.env.NODE_ENV) {
+      delete rootElementsByReactRootID[reactRootID];
+    }
+    return true;
+  },
+
+  /**
+   * Unmounts a component and removes it from the DOM.
+   *
+   * @param {ReactComponent} instance React component instance.
+   * @param {DOMElement} container DOM element to unmount from.
+   * @final
+   * @internal
+   * @see {ReactMount.unmountComponentAtNode}
+   */
+  unmountComponentFromNode: function(instance, container) {
+    ReactReconciler.unmountComponent(instance);
+
+    if (container.nodeType === DOC_NODE_TYPE) {
+      container = container.documentElement;
+    }
+
+    // http://jsperf.com/emptying-a-node
+    while (container.lastChild) {
+      container.removeChild(container.lastChild);
+    }
+  },
+
+  /**
+   * Finds the container DOM element that contains React component to which the
+   * supplied DOM `id` belongs.
+   *
+   * @param {string} id The ID of an element rendered by a React component.
+   * @return {?DOMElement} DOM element that contains the `id`.
+   */
+  findReactContainerForID: function(id) {
+    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
+    var container = containersByReactRootID[reactRootID];
+
+    if ("production" !== process.env.NODE_ENV) {
+      var rootElement = rootElementsByReactRootID[reactRootID];
+      if (rootElement && rootElement.parentNode !== container) {
+        ("production" !== process.env.NODE_ENV ? invariant(
+          // Call internalGetID here because getID calls isValid which calls
+          // findReactContainerForID (this function).
+          internalGetID(rootElement) === reactRootID,
+          'ReactMount: Root element ID differed from reactRootID.'
+        ) : invariant(// Call internalGetID here because getID calls isValid which calls
+        // findReactContainerForID (this function).
+        internalGetID(rootElement) === reactRootID));
+
+        var containerChild = container.firstChild;
+        if (containerChild &&
+            reactRootID === internalGetID(containerChild)) {
+          // If the container has a new child with the same ID as the old
+          // root element, then rootElementsByReactRootID[reactRootID] is
+          // just stale and needs to be updated. The case that deserves a
+          // warning is when the container is empty.
+          rootElementsByReactRootID[reactRootID] = containerChild;
+        } else {
+          ("production" !== process.env.NODE_ENV ? warning(
+            false,
+            'ReactMount: Root element has been removed from its original ' +
+            'container. New container:', rootElement.parentNode
+          ) : null);
+        }
+      }
+    }
+
+    return container;
+  },
+
+  /**
+   * Finds an element rendered by React with the supplied ID.
+   *
+   * @param {string} id ID of a DOM node in the React component.
+   * @return {DOMElement} Root DOM node of the React component.
+   */
+  findReactNodeByID: function(id) {
+    var reactRoot = ReactMount.findReactContainerForID(id);
+    return ReactMount.findComponentRoot(reactRoot, id);
+  },
+
+  /**
+   * True if the supplied `node` is rendered by React.
+   *
+   * @param {*} node DOM Element to check.
+   * @return {boolean} True if the DOM Element appears to be rendered by React.
+   * @internal
+   */
+  isRenderedByReact: function(node) {
+    if (node.nodeType !== 1) {
+      // Not a DOMElement, therefore not a React component
+      return false;
+    }
+    var id = ReactMount.getID(node);
+    return id ? id.charAt(0) === SEPARATOR : false;
+  },
+
+  /**
+   * Traverses up the ancestors of the supplied node to find a node that is a
+   * DOM representation of a React component.
+   *
+   * @param {*} node
+   * @return {?DOMEventTarget}
+   * @internal
+   */
+  getFirstReactDOM: function(node) {
+    var current = node;
+    while (current && current.parentNode !== current) {
+      if (ReactMount.isRenderedByReact(current)) {
+        return current;
+      }
+      current = current.parentNode;
+    }
+    return null;
+  },
+
+  /**
+   * Finds a node with the supplied `targetID` inside of the supplied
+   * `ancestorNode`.  Exploits the ID naming scheme to perform the search
+   * quickly.
+   *
+   * @param {DOMEventTarget} ancestorNode Search from this root.
+   * @pararm {string} targetID ID of the DOM representation of the component.
+   * @return {DOMEventTarget} DOM node with the supplied `targetID`.
+   * @internal
+   */
+  findComponentRoot: function(ancestorNode, targetID) {
+    var firstChildren = findComponentRootReusableArray;
+    var childIndex = 0;
+
+    var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;
+
+    firstChildren[0] = deepestAncestor.firstChild;
+    firstChildren.length = 1;
+
+    while (childIndex < firstChildren.length) {
+      var child = firstChildren[childIndex++];
+      var targetChild;
+
+      while (child) {
+        var childID = ReactMount.getID(child);
+        if (childID) {
+          // Even if we find the node we're looking for, we finish looping
+          // through its siblings to ensure they're cached so that we don't have
+          // to revisit this node again. Otherwise, we make n^2 calls to getID
+          // when visiting the many children of a single node in order.
+
+          if (targetID === childID) {
+            targetChild = child;
+          } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
+            // If we find a child whose ID is an ancestor of the given ID,
+            // then we can be sure that we only want to search the subtree
+            // rooted at this child, so we can throw out the rest of the
+            // search state.
+            firstChildren.length = childIndex = 0;
+            firstChildren.push(child.firstChild);
+          }
+
+        } else {
+          // If this child had no ID, then there's a chance that it was
+          // injected automatically by the browser, as when a `<table>`
+          // element sprouts an extra `<tbody>` child as a side effect of
+          // `.innerHTML` parsing. Optimistically continue down this
+          // branch, but not before examining the other siblings.
+          firstChildren.push(child.firstChild);
+        }
+
+        child = child.nextSibling;
+      }
+
+      if (targetChild) {
+        // Emptying firstChildren/findComponentRootReusableArray is
+        // not necessary for correctness, but it helps the GC reclaim
+        // any nodes that were left at the end of the search.
+        firstChildren.length = 0;
+
+        return targetChild;
+      }
+    }
+
+    firstChildren.length = 0;
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      false,
+      'findComponentRoot(..., %s): Unable to find element. This probably ' +
+      'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
+      'usually due to forgetting a <tbody> when using tables, nesting tags ' +
+      'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
+      'parent. ' +
+      'Try inspecting the child nodes of the element with React ID `%s`.',
+      targetID,
+      ReactMount.getID(ancestorNode)
+    ) : invariant(false));
+  },
+
+  _mountImageIntoNode: function(markup, container, shouldReuseMarkup) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      container && (
+        (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+      ),
+      'mountComponentIntoNode(...): Target container is not valid.'
+    ) : invariant(container && (
+      (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE)
+    )));
+
+    if (shouldReuseMarkup) {
+      var rootElement = getReactRootElementInContainer(container);
+      if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) {
+        return;
+      } else {
+        var checksum = rootElement.getAttribute(
+          ReactMarkupChecksum.CHECKSUM_ATTR_NAME
+        );
+        rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
+
+        var rootMarkup = rootElement.outerHTML;
+        rootElement.setAttribute(
+          ReactMarkupChecksum.CHECKSUM_ATTR_NAME,
+          checksum
+        );
+
+        var diffIndex = firstDifferenceIndex(markup, rootMarkup);
+        var difference = ' (client) ' +
+          markup.substring(diffIndex - 20, diffIndex + 20) +
+          '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20);
+
+        ("production" !== process.env.NODE_ENV ? invariant(
+          container.nodeType !== DOC_NODE_TYPE,
+          'You\'re trying to render a component to the document using ' +
+          'server rendering but the checksum was invalid. This usually ' +
+          'means you rendered a different component type or props on ' +
+          'the client from the one on the server, or your render() ' +
+          'methods are impure. React cannot handle this case due to ' +
+          'cross-browser quirks by rendering at the document root. You ' +
+          'should look for environment dependent code in your components ' +
+          'and ensure the props are the same client and server side:\n%s',
+          difference
+        ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+        if ("production" !== process.env.NODE_ENV) {
+          ("production" !== process.env.NODE_ENV ? warning(
+            false,
+            'React attempted to reuse markup in a container but the ' +
+            'checksum was invalid. This generally means that you are ' +
+            'using server rendering and the markup generated on the ' +
+            'server was not what the client was expecting. React injected ' +
+            'new markup to compensate which works but you have lost many ' +
+            'of the benefits of server rendering. Instead, figure out ' +
+            'why the markup being generated is different on the client ' +
+            'or server:\n%s',
+            difference
+          ) : null);
+        }
+      }
+    }
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      container.nodeType !== DOC_NODE_TYPE,
+      'You\'re trying to render a component to the document but ' +
+        'you didn\'t use server rendering. We can\'t do this ' +
+        'without using server rendering due to cross-browser quirks. ' +
+        'See React.renderToString() for server rendering.'
+    ) : invariant(container.nodeType !== DOC_NODE_TYPE));
+
+    setInnerHTML(container, markup);
+  },
+
+  /**
+   * React ID utilities.
+   */
+
+  getReactRootID: getReactRootID,
+
+  getID: getID,
+
+  setID: setID,
+
+  getNode: getNode,
+
+  getNodeFromInstance: getNodeFromInstance,
+
+  purgeID: purgeID
+};
+
+ReactPerf.measureMethods(ReactMount, 'ReactMount', {
+  _renderNewRootComponent: '_renderNewRootComponent',
+  _mountImageIntoNode: '_mountImageIntoNode'
+});
+
+module.exports = ReactMount;
+
+}).call(this,require('_process'))
+},{"./DOMProperty":10,"./ReactBrowserEventEmitter":31,"./ReactCurrentOwner":40,"./ReactElement":58,"./ReactElementValidator":59,"./ReactEmptyComponent":60,"./ReactInstanceHandles":67,"./ReactInstanceMap":68,"./ReactMarkupChecksum":70,"./ReactPerf":76,"./ReactReconciler":82,"./ReactUpdateQueue":87,"./ReactUpdates":88,"./containsNode":110,"./emptyObject":116,"./getReactRootElementInContainer":130,"./instantiateReactComponent":135,"./invariant":136,"./setInnerHTML":149,"./shouldUpdateReactC [...]
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChild
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactComponentEnvironment = require("./ReactComponentEnvironment");
+var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");
+
+var ReactReconciler = require("./ReactReconciler");
+var ReactChildReconciler = require("./ReactChildReconciler");
+
+/**
+ * Updating children of a component may trigger recursive updates. The depth is
+ * used to batch recursive updates to render markup more efficiently.
+ *
+ * @type {number}
+ * @private
+ */
+var updateDepth = 0;
+
+/**
+ * Queue of update configuration objects.
+ *
+ * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
+ *
+ * @type {array<object>}
+ * @private
+ */
+var updateQueue = [];
+
+/**
+ * Queue of markup to be rendered.
+ *
+ * @type {array<string>}
+ * @private
+ */
+var markupQueue = [];
+
+/**
+ * Enqueues markup to be rendered and inserted at a supplied index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} markup Markup that renders into an element.
+ * @param {number} toIndex Destination index.
+ * @private
+ */
+function enqueueMarkup(parentID, markup, toIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
+    markupIndex: markupQueue.push(markup) - 1,
+    textContent: null,
+    fromIndex: null,
+    toIndex: toIndex
+  });
+}
+
+/**
+ * Enqueues moving an existing element to another index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Source index of the existing element.
+ * @param {number} toIndex Destination index of the element.
+ * @private
+ */
+function enqueueMove(parentID, fromIndex, toIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
+    markupIndex: null,
+    textContent: null,
+    fromIndex: fromIndex,
+    toIndex: toIndex
+  });
+}
+
+/**
+ * Enqueues removing an element at an index.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {number} fromIndex Index of the element to remove.
+ * @private
+ */
+function enqueueRemove(parentID, fromIndex) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.REMOVE_NODE,
+    markupIndex: null,
+    textContent: null,
+    fromIndex: fromIndex,
+    toIndex: null
+  });
+}
+
+/**
+ * Enqueues setting the text content.
+ *
+ * @param {string} parentID ID of the parent component.
+ * @param {string} textContent Text content to set.
+ * @private
+ */
+function enqueueTextContent(parentID, textContent) {
+  // NOTE: Null values reduce hidden classes.
+  updateQueue.push({
+    parentID: parentID,
+    parentNode: null,
+    type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
+    markupIndex: null,
+    textContent: textContent,
+    fromIndex: null,
+    toIndex: null
+  });
+}
+
+/**
+ * Processes any enqueued updates.
+ *
+ * @private
+ */
+function processQueue() {
+  if (updateQueue.length) {
+    ReactComponentEnvironment.processChildrenUpdates(
+      updateQueue,
+      markupQueue
+    );
+    clearQueue();
+  }
+}
+
+/**
+ * Clears any enqueued updates.
+ *
+ * @private
+ */
+function clearQueue() {
+  updateQueue.length = 0;
+  markupQueue.length = 0;
+}
+
+/**
+ * ReactMultiChild are capable of reconciling multiple children.
+ *
+ * @class ReactMultiChild
+ * @internal
+ */
+var ReactMultiChild = {
+
+  /**
+   * Provides common functionality for components that must reconcile multiple
+   * children. This is used by `ReactDOMComponent` to mount, update, and
+   * unmount child components.
+   *
+   * @lends {ReactMultiChild.prototype}
+   */
+  Mixin: {
+
+    /**
+     * Generates a "mount image" for each of the supplied children. In the case
+     * of `ReactDOMComponent`, a mount image is a string of markup.
+     *
+     * @param {?object} nestedChildren Nested child maps.
+     * @return {array} An array of mounted representations.
+     * @internal
+     */
+    mountChildren: function(nestedChildren, transaction, context) {
+      var children = ReactChildReconciler.instantiateChildren(
+        nestedChildren, transaction, context
+      );
+      this._renderedChildren = children;
+      var mountImages = [];
+      var index = 0;
+      for (var name in children) {
+        if (children.hasOwnProperty(name)) {
+          var child = children[name];
+          // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+          var rootID = this._rootNodeID + name;
+          var mountImage = ReactReconciler.mountComponent(
+            child,
+            rootID,
+            transaction,
+            context
+          );
+          child._mountIndex = index;
+          mountImages.push(mountImage);
+          index++;
+        }
+      }
+      return mountImages;
+    },
+
+    /**
+     * Replaces any rendered children with a text content string.
+     *
+     * @param {string} nextContent String of content.
+     * @internal
+     */
+    updateTextContent: function(nextContent) {
+      updateDepth++;
+      var errorThrown = true;
+      try {
+        var prevChildren = this._renderedChildren;
+        // Remove any rendered children.
+        ReactChildReconciler.unmountChildren(prevChildren);
+        // TODO: The setTextContent operation should be enough
+        for (var name in prevChildren) {
+          if (prevChildren.hasOwnProperty(name)) {
+            this._unmountChildByName(prevChildren[name], name);
+          }
+        }
+        // Set new text content.
+        this.setTextContent(nextContent);
+        errorThrown = false;
+      } finally {
+        updateDepth--;
+        if (!updateDepth) {
+          if (errorThrown) {
+            clearQueue();
+          } else {
+            processQueue();
+          }
+        }
+      }
+    },
+
+    /**
+     * Updates the rendered children with new children.
+     *
+     * @param {?object} nextNestedChildren Nested child maps.
+     * @param {ReactReconcileTransaction} transaction
+     * @internal
+     */
+    updateChildren: function(nextNestedChildren, transaction, context) {
+      updateDepth++;
+      var errorThrown = true;
+      try {
+        this._updateChildren(nextNestedChildren, transaction, context);
+        errorThrown = false;
+      } finally {
+        updateDepth--;
+        if (!updateDepth) {
+          if (errorThrown) {
+            clearQueue();
+          } else {
+            processQueue();
+          }
+        }
+
+      }
+    },
+
+    /**
+     * Improve performance by isolating this hot code path from the try/catch
+     * block in `updateChildren`.
+     *
+     * @param {?object} nextNestedChildren Nested child maps.
+     * @param {ReactReconcileTransaction} transaction
+     * @final
+     * @protected
+     */
+    _updateChildren: function(nextNestedChildren, transaction, context) {
+      var prevChildren = this._renderedChildren;
+      var nextChildren = ReactChildReconciler.updateChildren(
+        prevChildren, nextNestedChildren, transaction, context
+      );
+      this._renderedChildren = nextChildren;
+      if (!nextChildren && !prevChildren) {
+        return;
+      }
+      var name;
+      // `nextIndex` will increment for each child in `nextChildren`, but
+      // `lastIndex` will be the last index visited in `prevChildren`.
+      var lastIndex = 0;
+      var nextIndex = 0;
+      for (name in nextChildren) {
+        if (!nextChildren.hasOwnProperty(name)) {
+          continue;
+        }
+        var prevChild = prevChildren && prevChildren[name];
+        var nextChild = nextChildren[name];
+        if (prevChild === nextChild) {
+          this.moveChild(prevChild, nextIndex, lastIndex);
+          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+          prevChild._mountIndex = nextIndex;
+        } else {
+          if (prevChild) {
+            // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
+            lastIndex = Math.max(prevChild._mountIndex, lastIndex);
+            this._unmountChildByName(prevChild, name);
+          }
+          // The child must be instantiated before it's mounted.
+          this._mountChildByNameAtIndex(
+            nextChild, name, nextIndex, transaction, context
+          );
+        }
+        nextIndex++;
+      }
+      // Remove children that are no longer present.
+      for (name in prevChildren) {
+        if (prevChildren.hasOwnProperty(name) &&
+            !(nextChildren && nextChildren.hasOwnProperty(name))) {
+          this._unmountChildByName(prevChildren[name], name);
+        }
+      }
+    },
+
+    /**
+     * Unmounts all rendered children. This should be used to clean up children
+     * when this component is unmounted.
+     *
+     * @internal
+     */
+    unmountChildren: function() {
+      var renderedChildren = this._renderedChildren;
+      ReactChildReconciler.unmountChildren(renderedChildren);
+      this._renderedChildren = null;
+    },
+
+    /**
+     * Moves a child component to the supplied index.
+     *
+     * @param {ReactComponent} child Component to move.
+     * @param {number} toIndex Destination index of the element.
+     * @param {number} lastIndex Last index visited of the siblings of `child`.
+     * @protected
+     */
+    moveChild: function(child, toIndex, lastIndex) {
+      // If the index of `child` is less than `lastIndex`, then it needs to
+      // be moved. Otherwise, we do not need to move it because a child will be
+      // inserted or moved before `child`.
+      if (child._mountIndex < lastIndex) {
+        enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
+      }
+    },
+
+    /**
+     * Creates a child component.
+     *
+     * @param {ReactComponent} child Component to create.
+     * @param {string} mountImage Markup to insert.
+     * @protected
+     */
+    createChild: function(child, mountImage) {
+      enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
+    },
+
+    /**
+     * Removes a child component.
+     *
+     * @param {ReactComponent} child Child to remove.
+     * @protected
+     */
+    removeChild: function(child) {
+      enqueueRemove(this._rootNodeID, child._mountIndex);
+    },
+
+    /**
+     * Sets this text content string.
+     *
+     * @param {string} textContent Text content to set.
+     * @protected
+     */
+    setTextContent: function(textContent) {
+      enqueueTextContent(this._rootNodeID, textContent);
+    },
+
+    /**
+     * Mounts a child with the supplied name.
+     *
+     * NOTE: This is part of `updateChildren` and is here for readability.
+     *
+     * @param {ReactComponent} child Component to mount.
+     * @param {string} name Name of the child.
+     * @param {number} index Index at which to insert the child.
+     * @param {ReactReconcileTransaction} transaction
+     * @private
+     */
+    _mountChildByNameAtIndex: function(
+      child,
+      name,
+      index,
+      transaction,
+      context) {
+      // Inlined for performance, see `ReactInstanceHandles.createReactID`.
+      var rootID = this._rootNodeID + name;
+      var mountImage = ReactReconciler.mountComponent(
+        child,
+        rootID,
+        transaction,
+        context
+      );
+      child._mountIndex = index;
+      this.createChild(child, mountImage);
+    },
+
+    /**
+     * Unmounts a rendered child by name.
+     *
+     * NOTE: This is part of `updateChildren` and is here for readability.
+     *
+     * @param {ReactComponent} child Component to unmount.
+     * @param {string} name Name of the child in `this._renderedChildren`.
+     * @private
+     */
+    _unmountChildByName: function(child, name) {
+      this.removeChild(child);
+      child._mountIndex = null;
+    }
+
+  }
+
+};
+
+module.exports = ReactMultiChild;
+
+},{"./ReactChildReconciler":32,"./ReactComponentEnvironment":37,"./ReactMultiChildUpdateTypes":73,"./ReactReconciler":82}],73:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactMultiChildUpdateTypes
+ */
+
+'use strict';
+
+var keyMirror = require("./keyMirror");
+
+/**
+ * When a component's children are updated, a series of update configuration
+ * objects are created in order to batch and serialize the required changes.
+ *
+ * Enumerates all the possible types of update configurations.
+ *
+ * @internal
+ */
+var ReactMultiChildUpdateTypes = keyMirror({
+  INSERT_MARKUP: null,
+  MOVE_EXISTING: null,
+  REMOVE_NODE: null,
+  TEXT_CONTENT: null
+});
+
+module.exports = ReactMultiChildUpdateTypes;
+
+},{"./keyMirror":141}],74:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactNativeComponent
+ */
+
+'use strict';
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+
+var autoGenerateWrapperClass = null;
+var genericComponentClass = null;
+// This registry keeps track of wrapper classes around native tags
+var tagToComponentClass = {};
+var textComponentClass = null;
+
+var ReactNativeComponentInjection = {
+  // This accepts a class that receives the tag string. This is a catch all
+  // that can render any kind of tag.
+  injectGenericComponentClass: function(componentClass) {
+    genericComponentClass = componentClass;
+  },
+  // This accepts a text component class that takes the text string to be
+  // rendered as props.
+  injectTextComponentClass: function(componentClass) {
+    textComponentClass = componentClass;
+  },
+  // This accepts a keyed object with classes as values. Each key represents a
+  // tag. That particular tag will use this class instead of the generic one.
+  injectComponentClasses: function(componentClasses) {
+    assign(tagToComponentClass, componentClasses);
+  },
+  // Temporary hack since we expect DOM refs to behave like composites,
+  // for this release.
+  injectAutoWrapper: function(wrapperFactory) {
+    autoGenerateWrapperClass = wrapperFactory;
+  }
+};
+
+/**
+ * Get a composite component wrapper class for a specific tag.
+ *
+ * @param {ReactElement} element The tag for which to get the class.
+ * @return {function} The React class constructor function.
+ */
+function getComponentClassForElement(element) {
+  if (typeof element.type === 'function') {
+    return element.type;
+  }
+  var tag = element.type;
+  var componentClass = tagToComponentClass[tag];
+  if (componentClass == null) {
+    tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag);
+  }
+  return componentClass;
+}
+
+/**
+ * Get a native internal component class for a specific tag.
+ *
+ * @param {ReactElement} element The element to create.
+ * @return {function} The internal class constructor function.
+ */
+function createInternalComponent(element) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    genericComponentClass,
+    'There is no registered component for the tag %s',
+    element.type
+  ) : invariant(genericComponentClass));
+  return new genericComponentClass(element.type, element.props);
+}
+
+/**
+ * @param {ReactText} text
+ * @return {ReactComponent}
+ */
+function createInstanceForText(text) {
+  return new textComponentClass(text);
+}
+
+/**
+ * @param {ReactComponent} component
+ * @return {boolean}
+ */
+function isTextComponent(component) {
+  return component instanceof textComponentClass;
+}
+
+var ReactNativeComponent = {
+  getComponentClassForElement: getComponentClassForElement,
+  createInternalComponent: createInternalComponent,
+  createInstanceForText: createInstanceForText,
+  isTextComponent: isTextComponent,
+  injection: ReactNativeComponentInjection
+};
+
+module.exports = ReactNativeComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./invariant":136,"_process":157}],75:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactOwner
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ * ReactOwners are capable of storing references to owned components.
+ *
+ * All components are capable of //being// referenced by owner components, but
+ * only ReactOwner components are capable of //referencing// owned components.
+ * The named reference is known as a "ref".
+ *
+ * Refs are available when mounted and updated during reconciliation.
+ *
+ *   var MyComponent = React.createClass({
+ *     render: function() {
+ *       return (
+ *         <div onClick={this.handleClick}>
+ *           <CustomComponent ref="custom" />
+ *         </div>
+ *       );
+ *     },
+ *     handleClick: function() {
+ *       this.refs.custom.handleClick();
+ *     },
+ *     componentDidMount: function() {
+ *       this.refs.custom.initialize();
+ *     }
+ *   });
+ *
+ * Refs should rarely be used. When refs are used, they should only be done to
+ * control data that is not handled by React's data flow.
+ *
+ * @class ReactOwner
+ */
+var ReactOwner = {
+
+  /**
+   * @param {?object} object
+   * @return {boolean} True if `object` is a valid owner.
+   * @final
+   */
+  isValidOwner: function(object) {
+    return !!(
+      (object &&
+      typeof object.attachRef === 'function' && typeof object.detachRef === 'function')
+    );
+  },
+
+  /**
+   * Adds a component by ref to an owner component.
+   *
+   * @param {ReactComponent} component Component to reference.
+   * @param {string} ref Name by which to refer to the component.
+   * @param {ReactOwner} owner Component on which to record the ref.
+   * @final
+   * @internal
+   */
+  addComponentAsRefTo: function(component, ref, owner) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ReactOwner.isValidOwner(owner),
+      'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
+      'usually means that you\'re trying to add a ref to a component that ' +
+      'doesn\'t have an owner (that is, was not created inside of another ' +
+      'component\'s `render` method). Try rendering this component inside of ' +
+      'a new top-level component which will hold the ref.'
+    ) : invariant(ReactOwner.isValidOwner(owner)));
+    owner.attachRef(ref, component);
+  },
+
+  /**
+   * Removes a component by ref from an owner component.
+   *
+   * @param {ReactComponent} component Component to dereference.
+   * @param {string} ref Name of the ref to remove.
+   * @param {ReactOwner} owner Component on which the ref is recorded.
+   * @final
+   * @internal
+   */
+  removeComponentAsRefFrom: function(component, ref, owner) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ReactOwner.isValidOwner(owner),
+      'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
+      'usually means that you\'re trying to remove a ref to a component that ' +
+      'doesn\'t have an owner (that is, was not created inside of another ' +
+      'component\'s `render` method). Try rendering this component inside of ' +
+      'a new top-level component which will hold the ref.'
+    ) : invariant(ReactOwner.isValidOwner(owner)));
+    // Check that `component` is still the current ref because we do not want to
+    // detach the ref if another component stole it.
+    if (owner.getPublicInstance().refs[ref] === component.getPublicInstance()) {
+      owner.detachRef(ref);
+    }
+  }
+
+};
+
+module.exports = ReactOwner;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],76:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPerf
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * ReactPerf is a general AOP system designed to measure performance. This
+ * module only has the hooks: see ReactDefaultPerf for the analysis tool.
+ */
+var ReactPerf = {
+  /**
+   * Boolean to enable/disable measurement. Set to false by default to prevent
+   * accidental logging and perf loss.
+   */
+  enableMeasure: false,
+
+  /**
+   * Holds onto the measure function in use. By default, don't measure
+   * anything, but we'll override this if we inject a measure function.
+   */
+  storedMeasure: _noMeasure,
+
+  /**
+   * @param {object} object
+   * @param {string} objectName
+   * @param {object<string>} methodNames
+   */
+  measureMethods: function(object, objectName, methodNames) {
+    if ("production" !== process.env.NODE_ENV) {
+      for (var key in methodNames) {
+        if (!methodNames.hasOwnProperty(key)) {
+          continue;
+        }
+        object[key] = ReactPerf.measure(
+          objectName,
+          methodNames[key],
+          object[key]
+        );
+      }
+    }
+  },
+
+  /**
+   * Use this to wrap methods you want to measure. Zero overhead in production.
+   *
+   * @param {string} objName
+   * @param {string} fnName
+   * @param {function} func
+   * @return {function}
+   */
+  measure: function(objName, fnName, func) {
+    if ("production" !== process.env.NODE_ENV) {
+      var measuredFunc = null;
+      var wrapper = function() {
+        if (ReactPerf.enableMeasure) {
+          if (!measuredFunc) {
+            measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
+          }
+          return measuredFunc.apply(this, arguments);
+        }
+        return func.apply(this, arguments);
+      };
+      wrapper.displayName = objName + '_' + fnName;
+      return wrapper;
+    }
+    return func;
+  },
+
+  injection: {
+    /**
+     * @param {function} measure
+     */
+    injectMeasure: function(measure) {
+      ReactPerf.storedMeasure = measure;
+    }
+  }
+};
+
+/**
+ * Simply passes through the measured function, without measuring it.
+ *
+ * @param {string} objName
+ * @param {string} fnName
+ * @param {function} func
+ * @return {function}
+ */
+function _noMeasure(objName, fnName, func) {
+  return func;
+}
+
+module.exports = ReactPerf;
+
+}).call(this,require('_process'))
+},{"_process":157}],77:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocationNames
+ */
+
+'use strict';
+
+var ReactPropTypeLocationNames = {};
+
+if ("production" !== process.env.NODE_ENV) {
+  ReactPropTypeLocationNames = {
+    prop: 'prop',
+    context: 'context',
+    childContext: 'child context'
+  };
+}
+
+module.exports = ReactPropTypeLocationNames;
+
+}).call(this,require('_process'))
+},{"_process":157}],78:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypeLocations
+ */
+
+'use strict';
+
+var keyMirror = require("./keyMirror");
+
+var ReactPropTypeLocations = keyMirror({
+  prop: null,
+  context: null,
+  childContext: null
+});
+
+module.exports = ReactPropTypeLocations;
+
+},{"./keyMirror":141}],79:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPropTypes
+ */
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactFragment = require("./ReactFragment");
+var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
+
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Collection of methods that allow declaration and validation of props that are
+ * supplied to React components. Example usage:
+ *
+ *   var Props = require('ReactPropTypes');
+ *   var MyArticle = React.createClass({
+ *     propTypes: {
+ *       // An optional string prop named "description".
+ *       description: Props.string,
+ *
+ *       // A required enum prop named "category".
+ *       category: Props.oneOf(['News','Photos']).isRequired,
+ *
+ *       // A prop named "dialog" that requires an instance of Dialog.
+ *       dialog: Props.instanceOf(Dialog).isRequired
+ *     },
+ *     render: function() { ... }
+ *   });
+ *
+ * A more formal specification of how these methods are used:
+ *
+ *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
+ *   decl := ReactPropTypes.{type}(.isRequired)?
+ *
+ * Each and every declaration produces a function with the same signature. This
+ * allows the creation of custom validation functions. For example:
+ *
+ *  var MyLink = React.createClass({
+ *    propTypes: {
+ *      // An optional string or URI prop named "href".
+ *      href: function(props, propName, componentName) {
+ *        var propValue = props[propName];
+ *        if (propValue != null && typeof propValue !== 'string' &&
+ *            !(propValue instanceof URI)) {
+ *          return new Error(
+ *            'Expected a string or an URI for ' + propName + ' in ' +
+ *            componentName
+ *          );
+ *        }
+ *      }
+ *    },
+ *    render: function() {...}
+ *  });
+ *
+ * @internal
+ */
+
+var ANONYMOUS = '<<anonymous>>';
+
+var elementTypeChecker = createElementTypeChecker();
+var nodeTypeChecker = createNodeChecker();
+
+var ReactPropTypes = {
+  array: createPrimitiveTypeChecker('array'),
+  bool: createPrimitiveTypeChecker('boolean'),
+  func: createPrimitiveTypeChecker('function'),
+  number: createPrimitiveTypeChecker('number'),
+  object: createPrimitiveTypeChecker('object'),
+  string: createPrimitiveTypeChecker('string'),
+
+  any: createAnyTypeChecker(),
+  arrayOf: createArrayOfTypeChecker,
+  element: elementTypeChecker,
+  instanceOf: createInstanceTypeChecker,
+  node: nodeTypeChecker,
+  objectOf: createObjectOfTypeChecker,
+  oneOf: createEnumTypeChecker,
+  oneOfType: createUnionTypeChecker,
+  shape: createShapeTypeChecker
+};
+
+function createChainableTypeChecker(validate) {
+  function checkType(isRequired, props, propName, componentName, location) {
+    componentName = componentName || ANONYMOUS;
+    if (props[propName] == null) {
+      var locationName = ReactPropTypeLocationNames[location];
+      if (isRequired) {
+        return new Error(
+          ("Required " + locationName + " `" + propName + "` was not specified in ") +
+          ("`" + componentName + "`.")
+        );
+      }
+      return null;
+    } else {
+      return validate(props, propName, componentName, location);
+    }
+  }
+
+  var chainedCheckType = checkType.bind(null, false);
+  chainedCheckType.isRequired = checkType.bind(null, true);
+
+  return chainedCheckType;
+}
+
+function createPrimitiveTypeChecker(expectedType) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== expectedType) {
+      var locationName = ReactPropTypeLocationNames[location];
+      // `propValue` being instance of, say, date/regexp, pass the 'object'
+      // check, but we can offer a more precise error message here rather than
+      // 'of type `object`'.
+      var preciseType = getPreciseType(propValue);
+
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type `" + preciseType + "` ") +
+        ("supplied to `" + componentName + "`, expected `" + expectedType + "`.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createAnyTypeChecker() {
+  return createChainableTypeChecker(emptyFunction.thatReturns(null));
+}
+
+function createArrayOfTypeChecker(typeChecker) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    if (!Array.isArray(propValue)) {
+      var locationName = ReactPropTypeLocationNames[location];
+      var propType = getPropType(propValue);
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type ") +
+        ("`" + propType + "` supplied to `" + componentName + "`, expected an array.")
+      );
+    }
+    for (var i = 0; i < propValue.length; i++) {
+      var error = typeChecker(propValue, i, componentName, location);
+      if (error instanceof Error) {
+        return error;
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createElementTypeChecker() {
+  function validate(props, propName, componentName, location) {
+    if (!ReactElement.isValidElement(props[propName])) {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected a ReactElement.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createInstanceTypeChecker(expectedClass) {
+  function validate(props, propName, componentName, location) {
+    if (!(props[propName] instanceof expectedClass)) {
+      var locationName = ReactPropTypeLocationNames[location];
+      var expectedClassName = expectedClass.name || ANONYMOUS;
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected instance of `" + expectedClassName + "`.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createEnumTypeChecker(expectedValues) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    for (var i = 0; i < expectedValues.length; i++) {
+      if (propValue === expectedValues[i]) {
+        return null;
+      }
+    }
+
+    var locationName = ReactPropTypeLocationNames[location];
+    var valuesString = JSON.stringify(expectedValues);
+    return new Error(
+      ("Invalid " + locationName + " `" + propName + "` of value `" + propValue + "` ") +
+      ("supplied to `" + componentName + "`, expected one of " + valuesString + ".")
+    );
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createObjectOfTypeChecker(typeChecker) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== 'object') {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type ") +
+        ("`" + propType + "` supplied to `" + componentName + "`, expected an object.")
+      );
+    }
+    for (var key in propValue) {
+      if (propValue.hasOwnProperty(key)) {
+        var error = typeChecker(propValue, key, componentName, location);
+        if (error instanceof Error) {
+          return error;
+        }
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createUnionTypeChecker(arrayOfTypeCheckers) {
+  function validate(props, propName, componentName, location) {
+    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
+      var checker = arrayOfTypeCheckers[i];
+      if (checker(props, propName, componentName, location) == null) {
+        return null;
+      }
+    }
+
+    var locationName = ReactPropTypeLocationNames[location];
+    return new Error(
+      ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+      ("`" + componentName + "`.")
+    );
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createNodeChecker() {
+  function validate(props, propName, componentName, location) {
+    if (!isNode(props[propName])) {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
+        ("`" + componentName + "`, expected a ReactNode.")
+      );
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function createShapeTypeChecker(shapeTypes) {
+  function validate(props, propName, componentName, location) {
+    var propValue = props[propName];
+    var propType = getPropType(propValue);
+    if (propType !== 'object') {
+      var locationName = ReactPropTypeLocationNames[location];
+      return new Error(
+        ("Invalid " + locationName + " `" + propName + "` of type `" + propType + "` ") +
+        ("supplied to `" + componentName + "`, expected `object`.")
+      );
+    }
+    for (var key in shapeTypes) {
+      var checker = shapeTypes[key];
+      if (!checker) {
+        continue;
+      }
+      var error = checker(propValue, key, componentName, location);
+      if (error) {
+        return error;
+      }
+    }
+    return null;
+  }
+  return createChainableTypeChecker(validate);
+}
+
+function isNode(propValue) {
+  switch (typeof propValue) {
+    case 'number':
+    case 'string':
+    case 'undefined':
+      return true;
+    case 'boolean':
+      return !propValue;
+    case 'object':
+      if (Array.isArray(propValue)) {
+        return propValue.every(isNode);
+      }
+      if (propValue === null || ReactElement.isValidElement(propValue)) {
+        return true;
+      }
+      propValue = ReactFragment.extractIfFragment(propValue);
+      for (var k in propValue) {
+        if (!isNode(propValue[k])) {
+          return false;
+        }
+      }
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Equivalent of `typeof` but with special handling for array and regexp.
+function getPropType(propValue) {
+  var propType = typeof propValue;
+  if (Array.isArray(propValue)) {
+    return 'array';
+  }
+  if (propValue instanceof RegExp) {
+    // Old webkits (at least until Android 4.0) return 'function' rather than
+    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
+    // passes PropTypes.object.
+    return 'object';
+  }
+  return propType;
+}
+
+// This handles more types than `getPropType`. Only used for error messages.
+// See `createPrimitiveTypeChecker`.
+function getPreciseType(propValue) {
+  var propType = getPropType(propValue);
+  if (propType === 'object') {
+    if (propValue instanceof Date) {
+      return 'date';
+    } else if (propValue instanceof RegExp) {
+      return 'regexp';
+    }
+  }
+  return propType;
+}
+
+module.exports = ReactPropTypes;
+
+},{"./ReactElement":58,"./ReactFragment":64,"./ReactPropTypeLocationNames":77,"./emptyFunction":115}],80:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactPutListenerQueue
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+
+var assign = require("./Object.assign");
+
+function ReactPutListenerQueue() {
+  this.listenersToPut = [];
+}
+
+assign(ReactPutListenerQueue.prototype, {
+  enqueuePutListener: function(rootNodeID, propKey, propValue) {
+    this.listenersToPut.push({
+      rootNodeID: rootNodeID,
+      propKey: propKey,
+      propValue: propValue
+    });
+  },
+
+  putListeners: function() {
+    for (var i = 0; i < this.listenersToPut.length; i++) {
+      var listenerToPut = this.listenersToPut[i];
+      ReactBrowserEventEmitter.putListener(
+        listenerToPut.rootNodeID,
+        listenerToPut.propKey,
+        listenerToPut.propValue
+      );
+    }
+  },
+
+  reset: function() {
+    this.listenersToPut.length = 0;
+  },
+
+  destructor: function() {
+    this.reset();
+  }
+});
+
+PooledClass.addPoolingTo(ReactPutListenerQueue);
+
+module.exports = ReactPutListenerQueue;
+
+},{"./Object.assign":27,"./PooledClass":28,"./ReactBrowserEventEmitter":31}],81:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactReconcileTransaction
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CallbackQueue = require("./CallbackQueue");
+var PooledClass = require("./PooledClass");
+var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
+var ReactInputSelection = require("./ReactInputSelection");
+var ReactPutListenerQueue = require("./ReactPutListenerQueue");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+
+/**
+ * Ensures that, when possible, the selection range (currently selected text
+ * input) is not disturbed by performing the transaction.
+ */
+var SELECTION_RESTORATION = {
+  /**
+   * @return {Selection} Selection information.
+   */
+  initialize: ReactInputSelection.getSelectionInformation,
+  /**
+   * @param {Selection} sel Selection information returned from `initialize`.
+   */
+  close: ReactInputSelection.restoreSelection
+};
+
+/**
+ * Suppresses events (blur/focus) that could be inadvertently dispatched due to
+ * high level DOM manipulations (like temporarily removing a text input from the
+ * DOM).
+ */
+var EVENT_SUPPRESSION = {
+  /**
+   * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
+   * the reconciliation.
+   */
+  initialize: function() {
+    var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
+    ReactBrowserEventEmitter.setEnabled(false);
+    return currentlyEnabled;
+  },
+
+  /**
+   * @param {boolean} previouslyEnabled Enabled status of
+   *   `ReactBrowserEventEmitter` before the reconciliation occured. `close`
+   *   restores the previous value.
+   */
+  close: function(previouslyEnabled) {
+    ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
+  }
+};
+
+/**
+ * Provides a queue for collecting `componentDidMount` and
+ * `componentDidUpdate` callbacks during the the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+  /**
+   * Initializes the internal `onDOMReady` queue.
+   */
+  initialize: function() {
+    this.reactMountReady.reset();
+  },
+
+  /**
+   * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
+   */
+  close: function() {
+    this.reactMountReady.notifyAll();
+  }
+};
+
+var PUT_LISTENER_QUEUEING = {
+  initialize: function() {
+    this.putListenerQueue.reset();
+  },
+
+  close: function() {
+    this.putListenerQueue.putListeners();
+  }
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+  PUT_LISTENER_QUEUEING,
+  SELECTION_RESTORATION,
+  EVENT_SUPPRESSION,
+  ON_DOM_READY_QUEUEING
+];
+
+/**
+ * Currently:
+ * - The order that these are listed in the transaction is critical:
+ * - Suppresses events.
+ * - Restores selection range.
+ *
+ * Future:
+ * - Restore document/overflow scroll positions that were unintentionally
+ *   modified via DOM insertions above the top viewport boundary.
+ * - Implement/integrate with customized constraint based layout system and keep
+ *   track of which dimensions must be remeasured.
+ *
+ * @class ReactReconcileTransaction
+ */
+function ReactReconcileTransaction() {
+  this.reinitializeTransaction();
+  // Only server-side rendering really needs this option (see
+  // `ReactServerRendering`), but server-side uses
+  // `ReactServerRenderingTransaction` instead. This option is here so that it's
+  // accessible and defaults to false when `ReactDOMComponent` and
+  // `ReactTextComponent` checks it in `mountComponent`.`
+  this.renderToStaticMarkup = false;
+  this.reactMountReady = CallbackQueue.getPooled(null);
+  this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+  /**
+   * @see Transaction
+   * @abstract
+   * @final
+   * @return {array<object>} List of operation wrap proceedures.
+   *   TODO: convert to array<TransactionWrapper>
+   */
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  /**
+   * @return {object} The queue to collect `onDOMReady` callbacks with.
+   */
+  getReactMountReady: function() {
+    return this.reactMountReady;
+  },
+
+  getPutListenerQueue: function() {
+    return this.putListenerQueue;
+  },
+
+  /**
+   * `PooledClass` looks for this, and will invoke this before allowing this
+   * instance to be resused.
+   */
+  destructor: function() {
+    CallbackQueue.release(this.reactMountReady);
+    this.reactMountReady = null;
+
+    ReactPutListenerQueue.release(this.putListenerQueue);
+    this.putListenerQueue = null;
+  }
+};
+
+
+assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);
+
+PooledClass.addPoolingTo(ReactReconcileTransaction);
+
+module.exports = ReactReconcileTransaction;
+
+},{"./CallbackQueue":6,"./Object.assign":27,"./PooledClass":28,"./ReactBrowserEventEmitter":31,"./ReactInputSelection":66,"./ReactPutListenerQueue":80,"./Transaction":104}],82:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactReconciler
+ */
+
+'use strict';
+
+var ReactRef = require("./ReactRef");
+var ReactElementValidator = require("./ReactElementValidator");
+
+/**
+ * Helper to call ReactRef.attachRefs with this composite component, split out
+ * to avoid allocations in the transaction mount-ready queue.
+ */
+function attachRefs() {
+  ReactRef.attachRefs(this, this._currentElement);
+}
+
+var ReactReconciler = {
+
+  /**
+   * Initializes the component, renders markup, and registers event listeners.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {string} rootID DOM ID of the root node.
+   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
+   * @return {?string} Rendered markup to be inserted into the DOM.
+   * @final
+   * @internal
+   */
+  mountComponent: function(internalInstance, rootID, transaction, context) {
+    var markup = internalInstance.mountComponent(rootID, transaction, context);
+    if ("production" !== process.env.NODE_ENV) {
+      ReactElementValidator.checkAndWarnForMutatedProps(
+        internalInstance._currentElement
+      );
+    }
+    transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
+    return markup;
+  },
+
+  /**
+   * Releases any resources allocated by `mountComponent`.
+   *
+   * @final
+   * @internal
+   */
+  unmountComponent: function(internalInstance) {
+    ReactRef.detachRefs(internalInstance, internalInstance._currentElement);
+    internalInstance.unmountComponent();
+  },
+
+  /**
+   * Update a component using a new element.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {ReactElement} nextElement
+   * @param {ReactReconcileTransaction} transaction
+   * @param {object} context
+   * @internal
+   */
+  receiveComponent: function(
+    internalInstance, nextElement, transaction, context
+  ) {
+    var prevElement = internalInstance._currentElement;
+
+    if (nextElement === prevElement && nextElement._owner != null) {
+      // Since elements are immutable after the owner is rendered,
+      // we can do a cheap identity compare here to determine if this is a
+      // superfluous reconcile. It's possible for state to be mutable but such
+      // change should trigger an update of the owner which would recreate
+      // the element. We explicitly check for the existence of an owner since
+      // it's possible for an element created outside a composite to be
+      // deeply mutated and reused.
+      return;
+    }
+
+    if ("production" !== process.env.NODE_ENV) {
+      ReactElementValidator.checkAndWarnForMutatedProps(nextElement);
+    }
+
+    var refsChanged = ReactRef.shouldUpdateRefs(
+      prevElement,
+      nextElement
+    );
+
+    if (refsChanged) {
+      ReactRef.detachRefs(internalInstance, prevElement);
+    }
+
+    internalInstance.receiveComponent(nextElement, transaction, context);
+
+    if (refsChanged) {
+      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
+    }
+  },
+
+  /**
+   * Flush any dirty changes in a component.
+   *
+   * @param {ReactComponent} internalInstance
+   * @param {ReactReconcileTransaction} transaction
+   * @internal
+   */
+  performUpdateIfNecessary: function(
+    internalInstance,
+    transaction
+  ) {
+    internalInstance.performUpdateIfNecessary(transaction);
+  }
+
+};
+
+module.exports = ReactReconciler;
+
+}).call(this,require('_process'))
+},{"./ReactElementValidator":59,"./ReactRef":83,"_process":157}],83:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactRef
+ */
+
+'use strict';
+
+var ReactOwner = require("./ReactOwner");
+
+var ReactRef = {};
+
+function attachRef(ref, component, owner) {
+  if (typeof ref === 'function') {
+    ref(component.getPublicInstance());
+  } else {
+    // Legacy ref
+    ReactOwner.addComponentAsRefTo(component, ref, owner);
+  }
+}
+
+function detachRef(ref, component, owner) {
+  if (typeof ref === 'function') {
+    ref(null);
+  } else {
+    // Legacy ref
+    ReactOwner.removeComponentAsRefFrom(component, ref, owner);
+  }
+}
+
+ReactRef.attachRefs = function(instance, element) {
+  var ref = element.ref;
+  if (ref != null) {
+    attachRef(ref, instance, element._owner);
+  }
+};
+
+ReactRef.shouldUpdateRefs = function(prevElement, nextElement) {
+  // If either the owner or a `ref` has changed, make sure the newest owner
+  // has stored a reference to `this`, and the previous owner (if different)
+  // has forgotten the reference to `this`. We use the element instead
+  // of the public this.props because the post processing cannot determine
+  // a ref. The ref conceptually lives on the element.
+
+  // TODO: Should this even be possible? The owner cannot change because
+  // it's forbidden by shouldUpdateReactComponent. The ref can change
+  // if you swap the keys of but not the refs. Reconsider where this check
+  // is made. It probably belongs where the key checking and
+  // instantiateReactComponent is done.
+
+  return (
+    nextElement._owner !== prevElement._owner ||
+    nextElement.ref !== prevElement.ref
+  );
+};
+
+ReactRef.detachRefs = function(instance, element) {
+  var ref = element.ref;
+  if (ref != null) {
+    detachRef(ref, instance, element._owner);
+  }
+};
+
+module.exports = ReactRef;
+
+},{"./ReactOwner":75}],84:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+var ReactRootIndexInjection = {
+  /**
+   * @param {function} _createReactRootIndex
+   */
+  injectCreateReactRootIndex: function(_createReactRootIndex) {
+    ReactRootIndex.createReactRootIndex = _createReactRootIndex;
+  }
+};
+
+var ReactRootIndex = {
+  createReactRootIndex: null,
+  injection: ReactRootIndexInjection
+};
+
+module.exports = ReactRootIndex;
+
+},{}],85:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks static-only
+ * @providesModule ReactServerRendering
+ */
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+var ReactMarkupChecksum = require("./ReactMarkupChecksum");
+var ReactServerRenderingTransaction =
+  require("./ReactServerRenderingTransaction");
+
+var emptyObject = require("./emptyObject");
+var instantiateReactComponent = require("./instantiateReactComponent");
+var invariant = require("./invariant");
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup
+ */
+function renderToString(element) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    ReactElement.isValidElement(element),
+    'renderToString(): You must pass a valid ReactElement.'
+  ) : invariant(ReactElement.isValidElement(element)));
+
+  var transaction;
+  try {
+    var id = ReactInstanceHandles.createReactRootID();
+    transaction = ReactServerRenderingTransaction.getPooled(false);
+
+    return transaction.perform(function() {
+      var componentInstance = instantiateReactComponent(element, null);
+      var markup =
+        componentInstance.mountComponent(id, transaction, emptyObject);
+      return ReactMarkupChecksum.addChecksumToMarkup(markup);
+    }, null);
+  } finally {
+    ReactServerRenderingTransaction.release(transaction);
+  }
+}
+
+/**
+ * @param {ReactElement} element
+ * @return {string} the HTML markup, without the extra React ID and checksum
+ * (for generating static pages)
+ */
+function renderToStaticMarkup(element) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    ReactElement.isValidElement(element),
+    'renderToStaticMarkup(): You must pass a valid ReactElement.'
+  ) : invariant(ReactElement.isValidElement(element)));
+
+  var transaction;
+  try {
+    var id = ReactInstanceHandles.createReactRootID();
+    transaction = ReactServerRenderingTransaction.getPooled(true);
+
+    return transaction.perform(function() {
+      var componentInstance = instantiateReactComponent(element, null);
+      return componentInstance.mountComponent(id, transaction, emptyObject);
+    }, null);
+  } finally {
+    ReactServerRenderingTransaction.release(transaction);
+  }
+}
+
+module.exports = {
+  renderToString: renderToString,
+  renderToStaticMarkup: renderToStaticMarkup
+};
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./ReactInstanceHandles":67,"./ReactMarkupChecksum":70,"./ReactServerRenderingTransaction":86,"./emptyObject":116,"./instantiateReactComponent":135,"./invariant":136,"_process":157}],86:[function(require,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactServerRenderingTransaction
+ * @typechecks
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+var CallbackQueue = require("./CallbackQueue");
+var ReactPutListenerQueue = require("./ReactPutListenerQueue");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
+ * during the performing of the transaction.
+ */
+var ON_DOM_READY_QUEUEING = {
+  /**
+   * Initializes the internal `onDOMReady` queue.
+   */
+  initialize: function() {
+    this.reactMountReady.reset();
+  },
+
+  close: emptyFunction
+};
+
+var PUT_LISTENER_QUEUEING = {
+  initialize: function() {
+    this.putListenerQueue.reset();
+  },
+
+  close: emptyFunction
+};
+
+/**
+ * Executed within the scope of the `Transaction` instance. Consider these as
+ * being member methods, but with an implied ordering while being isolated from
+ * each other.
+ */
+var TRANSACTION_WRAPPERS = [
+  PUT_LISTENER_QUEUEING,
+  ON_DOM_READY_QUEUEING
+];
+
+/**
+ * @class ReactServerRenderingTransaction
+ * @param {boolean} renderToStaticMarkup
+ */
+function ReactServerRenderingTransaction(renderToStaticMarkup) {
+  this.reinitializeTransaction();
+  this.renderToStaticMarkup = renderToStaticMarkup;
+  this.reactMountReady = CallbackQueue.getPooled(null);
+  this.putListenerQueue = ReactPutListenerQueue.getPooled();
+}
+
+var Mixin = {
+  /**
+   * @see Transaction
+   * @abstract
+   * @final
+   * @return {array} Empty list of operation wrap proceedures.
+   */
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  /**
+   * @return {object} The queue to collect `onDOMReady` callbacks with.
+   */
+  getReactMountReady: function() {
+    return this.reactMountReady;
+  },
+
+  getPutListenerQueue: function() {
+    return this.putListenerQueue;
+  },
+
+  /**
+   * `PooledClass` looks for this, and will invoke this before allowing this
+   * instance to be resused.
+   */
+  destructor: function() {
+    CallbackQueue.release(this.reactMountReady);
+    this.reactMountReady = null;
+
+    ReactPutListenerQueue.release(this.putListenerQueue);
+    this.putListenerQueue = null;
+  }
+};
+
+
+assign(
+  ReactServerRenderingTransaction.prototype,
+  Transaction.Mixin,
+  Mixin
+);
+
+PooledClass.addPoolingTo(ReactServerRenderingTransaction);
+
+module.exports = ReactServerRenderingTransaction;
+
+},{"./CallbackQueue":6,"./Object.assign":27,"./PooledClass":28,"./ReactPutListenerQueue":80,"./Transaction":104,"./emptyFunction":115}],87:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactUpdateQueue
+ */
+
+'use strict';
+
+var ReactLifeCycle = require("./ReactLifeCycle");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactElement = require("./ReactElement");
+var ReactInstanceMap = require("./ReactInstanceMap");
+var ReactUpdates = require("./ReactUpdates");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+function enqueueUpdate(internalInstance) {
+  if (internalInstance !== ReactLifeCycle.currentlyMountingInstance) {
+    // If we're in a componentWillMount handler, don't enqueue a rerender
+    // because ReactUpdates assumes we're in a browser context (which is
+    // wrong for server rendering) and we're about to do a render anyway.
+    // See bug in #1740.
+    ReactUpdates.enqueueUpdate(internalInstance);
+  }
+}
+
+function getInternalInstanceReadyForUpdate(publicInstance, callerName) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    ReactCurrentOwner.current == null,
+    '%s(...): Cannot update during an existing state transition ' +
+    '(such as within `render`). Render methods should be a pure function ' +
+    'of props and state.',
+    callerName
+  ) : invariant(ReactCurrentOwner.current == null));
+
+  var internalInstance = ReactInstanceMap.get(publicInstance);
+  if (!internalInstance) {
+    if ("production" !== process.env.NODE_ENV) {
+      // Only warn when we have a callerName. Otherwise we should be silent.
+      // We're probably calling from enqueueCallback. We don't want to warn
+      // there because we already warned for the corresponding lifecycle method.
+      ("production" !== process.env.NODE_ENV ? warning(
+        !callerName,
+        '%s(...): Can only update a mounted or mounting component. ' +
+        'This usually means you called %s() on an unmounted ' +
+        'component. This is a no-op.',
+        callerName,
+        callerName
+      ) : null);
+    }
+    return null;
+  }
+
+  if (internalInstance === ReactLifeCycle.currentlyUnmountingInstance) {
+    return null;
+  }
+
+  return internalInstance;
+}
+
+/**
+ * ReactUpdateQueue allows for state updates to be scheduled into a later
+ * reconciliation step.
+ */
+var ReactUpdateQueue = {
+
+  /**
+   * Enqueue a callback that will be executed after all the pending updates
+   * have processed.
+   *
+   * @param {ReactClass} publicInstance The instance to use as `this` context.
+   * @param {?function} callback Called after state is updated.
+   * @internal
+   */
+  enqueueCallback: function(publicInstance, callback) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      typeof callback === 'function',
+      'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
+      '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
+      'isn\'t callable.'
+    ) : invariant(typeof callback === 'function'));
+    var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
+
+    // Previously we would throw an error if we didn't have an internal
+    // instance. Since we want to make it a no-op instead, we mirror the same
+    // behavior we have in other enqueue* methods.
+    // We also need to ignore callbacks in componentWillMount. See
+    // enqueueUpdates.
+    if (!internalInstance ||
+        internalInstance === ReactLifeCycle.currentlyMountingInstance) {
+      return null;
+    }
+
+    if (internalInstance._pendingCallbacks) {
+      internalInstance._pendingCallbacks.push(callback);
+    } else {
+      internalInstance._pendingCallbacks = [callback];
+    }
+    // TODO: The callback here is ignored when setState is called from
+    // componentWillMount. Either fix it or disallow doing so completely in
+    // favor of getInitialState. Alternatively, we can disallow
+    // componentWillMount during server-side rendering.
+    enqueueUpdate(internalInstance);
+  },
+
+  enqueueCallbackInternal: function(internalInstance, callback) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      typeof callback === 'function',
+      'enqueueCallback(...): You called `setProps`, `replaceProps`, ' +
+      '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
+      'isn\'t callable.'
+    ) : invariant(typeof callback === 'function'));
+    if (internalInstance._pendingCallbacks) {
+      internalInstance._pendingCallbacks.push(callback);
+    } else {
+      internalInstance._pendingCallbacks = [callback];
+    }
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Forces an update. This should only be invoked when it is known with
+   * certainty that we are **not** in a DOM transaction.
+   *
+   * You may want to call this when you know that some deeper aspect of the
+   * component's state has changed but `setState` was not called.
+   *
+   * This will not invoke `shouldUpdateComponent`, but it will invoke
+   * `componentWillUpdate` and `componentDidUpdate`.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @internal
+   */
+  enqueueForceUpdate: function(publicInstance) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'forceUpdate'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    internalInstance._pendingForceUpdate = true;
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Replaces all of the state. Always use this or `setState` to mutate state.
+   * You should treat `this.state` as immutable.
+   *
+   * There is no guarantee that `this.state` will be immediately updated, so
+   * accessing `this.state` after calling this method may return the old value.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} completeState Next state.
+   * @internal
+   */
+  enqueueReplaceState: function(publicInstance, completeState) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'replaceState'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    internalInstance._pendingStateQueue = [completeState];
+    internalInstance._pendingReplaceState = true;
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Sets a subset of the state. This only exists because _pendingState is
+   * internal. This provides a merging strategy that is not available to deep
+   * properties which is confusing. TODO: Expose pendingState or don't use it
+   * during the merge.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} partialState Next partial state to be merged with state.
+   * @internal
+   */
+  enqueueSetState: function(publicInstance, partialState) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'setState'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    var queue =
+      internalInstance._pendingStateQueue ||
+      (internalInstance._pendingStateQueue = []);
+    queue.push(partialState);
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Sets a subset of the props.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} partialProps Subset of the next props.
+   * @internal
+   */
+  enqueueSetProps: function(publicInstance, partialProps) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'setProps'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      internalInstance._isTopLevel,
+      'setProps(...): You called `setProps` on a ' +
+      'component with a parent. This is an anti-pattern since props will ' +
+      'get reactively updated when rendered. Instead, change the owner\'s ' +
+      '`render` method to pass the correct value as props to the component ' +
+      'where it is created.'
+    ) : invariant(internalInstance._isTopLevel));
+
+    // Merge with the pending element if it exists, otherwise with existing
+    // element props.
+    var element = internalInstance._pendingElement ||
+                  internalInstance._currentElement;
+    var props = assign({}, element.props, partialProps);
+    internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      props
+    );
+
+    enqueueUpdate(internalInstance);
+  },
+
+  /**
+   * Replaces all of the props.
+   *
+   * @param {ReactClass} publicInstance The instance that should rerender.
+   * @param {object} props New props.
+   * @internal
+   */
+  enqueueReplaceProps: function(publicInstance, props) {
+    var internalInstance = getInternalInstanceReadyForUpdate(
+      publicInstance,
+      'replaceProps'
+    );
+
+    if (!internalInstance) {
+      return;
+    }
+
+    ("production" !== process.env.NODE_ENV ? invariant(
+      internalInstance._isTopLevel,
+      'replaceProps(...): You called `replaceProps` on a ' +
+      'component with a parent. This is an anti-pattern since props will ' +
+      'get reactively updated when rendered. Instead, change the owner\'s ' +
+      '`render` method to pass the correct value as props to the component ' +
+      'where it is created.'
+    ) : invariant(internalInstance._isTopLevel));
+
+    // Merge with the pending element if it exists, otherwise with existing
+    // element props.
+    var element = internalInstance._pendingElement ||
+                  internalInstance._currentElement;
+    internalInstance._pendingElement = ReactElement.cloneAndReplaceProps(
+      element,
+      props
+    );
+
+    enqueueUpdate(internalInstance);
+  },
+
+  enqueueElementInternal: function(internalInstance, newElement) {
+    internalInstance._pendingElement = newElement;
+    enqueueUpdate(internalInstance);
+  }
+
+};
+
+module.exports = ReactUpdateQueue;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./ReactCurrentOwner":40,"./ReactElement":58,"./ReactInstanceMap":68,"./ReactLifeCycle":69,"./ReactUpdates":88,"./invariant":136,"./warning":155,"_process":157}],88:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactUpdates
+ */
+
+'use strict';
+
+var CallbackQueue = require("./CallbackQueue");
+var PooledClass = require("./PooledClass");
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactPerf = require("./ReactPerf");
+var ReactReconciler = require("./ReactReconciler");
+var Transaction = require("./Transaction");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+var dirtyComponents = [];
+var asapCallbackQueue = CallbackQueue.getPooled();
+var asapEnqueued = false;
+
+var batchingStrategy = null;
+
+function ensureInjected() {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    ReactUpdates.ReactReconcileTransaction && batchingStrategy,
+    'ReactUpdates: must inject a reconcile transaction class and batching ' +
+    'strategy'
+  ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy));
+}
+
+var NESTED_UPDATES = {
+  initialize: function() {
+    this.dirtyComponentsLength = dirtyComponents.length;
+  },
+  close: function() {
+    if (this.dirtyComponentsLength !== dirtyComponents.length) {
+      // Additional updates were enqueued by componentDidUpdate handlers or
+      // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
+      // these new updates so that if A's componentDidUpdate calls setState on
+      // B, B will update before the callback A's updater provided when calling
+      // setState.
+      dirtyComponents.splice(0, this.dirtyComponentsLength);
+      flushBatchedUpdates();
+    } else {
+      dirtyComponents.length = 0;
+    }
+  }
+};
+
+var UPDATE_QUEUEING = {
+  initialize: function() {
+    this.callbackQueue.reset();
+  },
+  close: function() {
+    this.callbackQueue.notifyAll();
+  }
+};
+
+var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];
+
+function ReactUpdatesFlushTransaction() {
+  this.reinitializeTransaction();
+  this.dirtyComponentsLength = null;
+  this.callbackQueue = CallbackQueue.getPooled();
+  this.reconcileTransaction =
+    ReactUpdates.ReactReconcileTransaction.getPooled();
+}
+
+assign(
+  ReactUpdatesFlushTransaction.prototype,
+  Transaction.Mixin, {
+  getTransactionWrappers: function() {
+    return TRANSACTION_WRAPPERS;
+  },
+
+  destructor: function() {
+    this.dirtyComponentsLength = null;
+    CallbackQueue.release(this.callbackQueue);
+    this.callbackQueue = null;
+    ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
+    this.reconcileTransaction = null;
+  },
+
+  perform: function(method, scope, a) {
+    // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
+    // with this transaction's wrappers around it.
+    return Transaction.Mixin.perform.call(
+      this,
+      this.reconcileTransaction.perform,
+      this.reconcileTransaction,
+      method,
+      scope,
+      a
+    );
+  }
+});
+
+PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);
+
+function batchedUpdates(callback, a, b, c, d) {
+  ensureInjected();
+  batchingStrategy.batchedUpdates(callback, a, b, c, d);
+}
+
+/**
+ * Array comparator for ReactComponents by mount ordering.
+ *
+ * @param {ReactComponent} c1 first component you're comparing
+ * @param {ReactComponent} c2 second component you're comparing
+ * @return {number} Return value usable by Array.prototype.sort().
+ */
+function mountOrderComparator(c1, c2) {
+  return c1._mountOrder - c2._mountOrder;
+}
+
+function runBatchedUpdates(transaction) {
+  var len = transaction.dirtyComponentsLength;
+  ("production" !== process.env.NODE_ENV ? invariant(
+    len === dirtyComponents.length,
+    'Expected flush transaction\'s stored dirty-components length (%s) to ' +
+    'match dirty-components array length (%s).',
+    len,
+    dirtyComponents.length
+  ) : invariant(len === dirtyComponents.length));
+
+  // Since reconciling a component higher in the owner hierarchy usually (not
+  // always -- see shouldComponentUpdate()) will reconcile children, reconcile
+  // them before their children by sorting the array.
+  dirtyComponents.sort(mountOrderComparator);
+
+  for (var i = 0; i < len; i++) {
+    // If a component is unmounted before pending changes apply, it will still
+    // be here, but we assume that it has cleared its _pendingCallbacks and
+    // that performUpdateIfNecessary is a noop.
+    var component = dirtyComponents[i];
+
+    // If performUpdateIfNecessary happens to enqueue any new updates, we
+    // shouldn't execute the callbacks until the next render happens, so
+    // stash the callbacks first
+    var callbacks = component._pendingCallbacks;
+    component._pendingCallbacks = null;
+
+    ReactReconciler.performUpdateIfNecessary(
+      component,
+      transaction.reconcileTransaction
+    );
+
+    if (callbacks) {
+      for (var j = 0; j < callbacks.length; j++) {
+        transaction.callbackQueue.enqueue(
+          callbacks[j],
+          component.getPublicInstance()
+        );
+      }
+    }
+  }
+}
+
+var flushBatchedUpdates = function() {
+  // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
+  // array and perform any updates enqueued by mount-ready handlers (i.e.,
+  // componentDidUpdate) but we need to check here too in order to catch
+  // updates enqueued by setState callbacks and asap calls.
+  while (dirtyComponents.length || asapEnqueued) {
+    if (dirtyComponents.length) {
+      var transaction = ReactUpdatesFlushTransaction.getPooled();
+      transaction.perform(runBatchedUpdates, null, transaction);
+      ReactUpdatesFlushTransaction.release(transaction);
+    }
+
+    if (asapEnqueued) {
+      asapEnqueued = false;
+      var queue = asapCallbackQueue;
+      asapCallbackQueue = CallbackQueue.getPooled();
+      queue.notifyAll();
+      CallbackQueue.release(queue);
+    }
+  }
+};
+flushBatchedUpdates = ReactPerf.measure(
+  'ReactUpdates',
+  'flushBatchedUpdates',
+  flushBatchedUpdates
+);
+
+/**
+ * Mark a component as needing a rerender, adding an optional callback to a
+ * list of functions which will be executed once the rerender occurs.
+ */
+function enqueueUpdate(component) {
+  ensureInjected();
+
+  // Various parts of our code (such as ReactCompositeComponent's
+  // _renderValidatedComponent) assume that calls to render aren't nested;
+  // verify that that's the case. (This is called by each top-level update
+  // function, like setProps, setState, forceUpdate, etc.; creation and
+  // destruction of top-level components is guarded in ReactMount.)
+  ("production" !== process.env.NODE_ENV ? warning(
+    ReactCurrentOwner.current == null,
+    'enqueueUpdate(): Render methods should be a pure function of props ' +
+    'and state; triggering nested component updates from render is not ' +
+    'allowed. If necessary, trigger nested updates in ' +
+    'componentDidUpdate.'
+  ) : null);
+
+  if (!batchingStrategy.isBatchingUpdates) {
+    batchingStrategy.batchedUpdates(enqueueUpdate, component);
+    return;
+  }
+
+  dirtyComponents.push(component);
+}
+
+/**
+ * Enqueue a callback to be run at the end of the current batching cycle. Throws
+ * if no updates are currently being performed.
+ */
+function asap(callback, context) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    batchingStrategy.isBatchingUpdates,
+    'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
+    'updates are not being batched.'
+  ) : invariant(batchingStrategy.isBatchingUpdates));
+  asapCallbackQueue.enqueue(callback, context);
+  asapEnqueued = true;
+}
+
+var ReactUpdatesInjection = {
+  injectReconcileTransaction: function(ReconcileTransaction) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      ReconcileTransaction,
+      'ReactUpdates: must provide a reconcile transaction class'
+    ) : invariant(ReconcileTransaction));
+    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
+  },
+
+  injectBatchingStrategy: function(_batchingStrategy) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      _batchingStrategy,
+      'ReactUpdates: must provide a batching strategy'
+    ) : invariant(_batchingStrategy));
+    ("production" !== process.env.NODE_ENV ? invariant(
+      typeof _batchingStrategy.batchedUpdates === 'function',
+      'ReactUpdates: must provide a batchedUpdates() function'
+    ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function'));
+    ("production" !== process.env.NODE_ENV ? invariant(
+      typeof _batchingStrategy.isBatchingUpdates === 'boolean',
+      'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
+    ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean'));
+    batchingStrategy = _batchingStrategy;
+  }
+};
+
+var ReactUpdates = {
+  /**
+   * React references `ReactReconcileTransaction` using this property in order
+   * to allow dependency injection.
+   *
+   * @internal
+   */
+  ReactReconcileTransaction: null,
+
+  batchedUpdates: batchedUpdates,
+  enqueueUpdate: enqueueUpdate,
+  flushBatchedUpdates: flushBatchedUpdates,
+  injection: ReactUpdatesInjection,
+  asap: asap
+};
+
+module.exports = ReactUpdates;
+
+}).call(this,require('_process'))
+},{"./CallbackQueue":6,"./Object.assign":27,"./PooledClass":28,"./ReactCurrentOwner":40,"./ReactPerf":76,"./ReactReconciler":82,"./Transaction":104,"./invariant":136,"./warning":155,"_process":157}],89:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SVGDOMPropertyConfig
+ */
+
+/*jslint bitwise: true*/
+
+'use strict';
+
+var DOMProperty = require("./DOMProperty");
+
+var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
+
+var SVGDOMPropertyConfig = {
+  Properties: {
+    cx: MUST_USE_ATTRIBUTE,
+    cy: MUST_USE_ATTRIBUTE,
+    d: MUST_USE_ATTRIBUTE,
+    dx: MUST_USE_ATTRIBUTE,
+    dy: MUST_USE_ATTRIBUTE,
+    fill: MUST_USE_ATTRIBUTE,
+    fillOpacity: MUST_USE_ATTRIBUTE,
+    fontFamily: MUST_USE_ATTRIBUTE,
+    fontSize: MUST_USE_ATTRIBUTE,
+    fx: MUST_USE_ATTRIBUTE,
+    fy: MUST_USE_ATTRIBUTE,
+    gradientTransform: MUST_USE_ATTRIBUTE,
+    gradientUnits: MUST_USE_ATTRIBUTE,
+    markerEnd: MUST_USE_ATTRIBUTE,
+    markerMid: MUST_USE_ATTRIBUTE,
+    markerStart: MUST_USE_ATTRIBUTE,
+    offset: MUST_USE_ATTRIBUTE,
+    opacity: MUST_USE_ATTRIBUTE,
+    patternContentUnits: MUST_USE_ATTRIBUTE,
+    patternUnits: MUST_USE_ATTRIBUTE,
+    points: MUST_USE_ATTRIBUTE,
+    preserveAspectRatio: MUST_USE_ATTRIBUTE,
+    r: MUST_USE_ATTRIBUTE,
+    rx: MUST_USE_ATTRIBUTE,
+    ry: MUST_USE_ATTRIBUTE,
+    spreadMethod: MUST_USE_ATTRIBUTE,
+    stopColor: MUST_USE_ATTRIBUTE,
+    stopOpacity: MUST_USE_ATTRIBUTE,
+    stroke: MUST_USE_ATTRIBUTE,
+    strokeDasharray: MUST_USE_ATTRIBUTE,
+    strokeLinecap: MUST_USE_ATTRIBUTE,
+    strokeOpacity: MUST_USE_ATTRIBUTE,
+    strokeWidth: MUST_USE_ATTRIBUTE,
+    textAnchor: MUST_USE_ATTRIBUTE,
+    transform: MUST_USE_ATTRIBUTE,
+    version: MUST_USE_ATTRIBUTE,
+    viewBox: MUST_USE_ATTRIBUTE,
+    x1: MUST_USE_ATTRIBUTE,
+    x2: MUST_USE_ATTRIBUTE,
+    x: MUST_USE_ATTRIBUTE,
+    y1: MUST_USE_ATTRIBUTE,
+    y2: MUST_USE_ATTRIBUTE,
+    y: MUST_USE_ATTRIBUTE
+  },
+  DOMAttributeNames: {
+    fillOpacity: 'fill-opacity',
+    fontFamily: 'font-family',
+    fontSize: 'font-size',
+    gradientTransform: 'gradientTransform',
+    gradientUnits: 'gradientUnits',
+    markerEnd: 'marker-end',
+    markerMid: 'marker-mid',
+    markerStart: 'marker-start',
+    patternContentUnits: 'patternContentUnits',
+    patternUnits: 'patternUnits',
+    preserveAspectRatio: 'preserveAspectRatio',
+    spreadMethod: 'spreadMethod',
+    stopColor: 'stop-color',
+    stopOpacity: 'stop-opacity',
+    strokeDasharray: 'stroke-dasharray',
+    strokeLinecap: 'stroke-linecap',
+    strokeOpacity: 'stroke-opacity',
+    strokeWidth: 'stroke-width',
+    textAnchor: 'text-anchor',
+    viewBox: 'viewBox'
+  }
+};
+
+module.exports = SVGDOMPropertyConfig;
+
+},{"./DOMProperty":10}],90:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SelectEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPropagators = require("./EventPropagators");
+var ReactInputSelection = require("./ReactInputSelection");
+var SyntheticEvent = require("./SyntheticEvent");
+
+var getActiveElement = require("./getActiveElement");
+var isTextInputElement = require("./isTextInputElement");
+var keyOf = require("./keyOf");
+var shallowEqual = require("./shallowEqual");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  select: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onSelect: null}),
+      captured: keyOf({onSelectCapture: null})
+    },
+    dependencies: [
+      topLevelTypes.topBlur,
+      topLevelTypes.topContextMenu,
+      topLevelTypes.topFocus,
+      topLevelTypes.topKeyDown,
+      topLevelTypes.topMouseDown,
+      topLevelTypes.topMouseUp,
+      topLevelTypes.topSelectionChange
+    ]
+  }
+};
+
+var activeElement = null;
+var activeElementID = null;
+var lastSelection = null;
+var mouseDown = false;
+
+/**
+ * Get an object which is a unique representation of the current selection.
+ *
+ * The return value will not be consistent across nodes or browsers, but
+ * two identical selections on the same node will return identical objects.
+ *
+ * @param {DOMElement} node
+ * @param {object}
+ */
+function getSelection(node) {
+  if ('selectionStart' in node &&
+      ReactInputSelection.hasSelectionCapabilities(node)) {
+    return {
+      start: node.selectionStart,
+      end: node.selectionEnd
+    };
+  } else if (window.getSelection) {
+    var selection = window.getSelection();
+    return {
+      anchorNode: selection.anchorNode,
+      anchorOffset: selection.anchorOffset,
+      focusNode: selection.focusNode,
+      focusOffset: selection.focusOffset
+    };
+  } else if (document.selection) {
+    var range = document.selection.createRange();
+    return {
+      parentElement: range.parentElement(),
+      text: range.text,
+      top: range.boundingTop,
+      left: range.boundingLeft
+    };
+  }
+}
+
+/**
+ * Poll selection to see whether it's changed.
+ *
+ * @param {object} nativeEvent
+ * @return {?SyntheticEvent}
+ */
+function constructSelectEvent(nativeEvent) {
+  // Ensure we have the right element, and that the user is not dragging a
+  // selection (this matches native `select` event behavior). In HTML5, select
+  // fires only on input and textarea thus if there's no focused element we
+  // won't dispatch.
+  if (mouseDown ||
+      activeElement == null ||
+      activeElement !== getActiveElement()) {
+    return null;
+  }
+
+  // Only fire when selection has actually changed.
+  var currentSelection = getSelection(activeElement);
+  if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
+    lastSelection = currentSelection;
+
+    var syntheticEvent = SyntheticEvent.getPooled(
+      eventTypes.select,
+      activeElementID,
+      nativeEvent
+    );
+
+    syntheticEvent.type = 'select';
+    syntheticEvent.target = activeElement;
+
+    EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);
+
+    return syntheticEvent;
+  }
+}
+
+/**
+ * This plugin creates an `onSelect` event that normalizes select events
+ * across form elements.
+ *
+ * Supported elements are:
+ * - input (see `isTextInputElement`)
+ * - textarea
+ * - contentEditable
+ *
+ * This differs from native browser implementations in the following ways:
+ * - Fires on contentEditable fields as well as inputs.
+ * - Fires for collapsed selection.
+ * - Fires after user input.
+ */
+var SelectEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+
+    switch (topLevelType) {
+      // Track the input node that has focus.
+      case topLevelTypes.topFocus:
+        if (isTextInputElement(topLevelTarget) ||
+            topLevelTarget.contentEditable === 'true') {
+          activeElement = topLevelTarget;
+          activeElementID = topLevelTargetID;
+          lastSelection = null;
+        }
+        break;
+      case topLevelTypes.topBlur:
+        activeElement = null;
+        activeElementID = null;
+        lastSelection = null;
+        break;
+
+      // Don't fire the event while the user is dragging. This matches the
+      // semantics of the native select event.
+      case topLevelTypes.topMouseDown:
+        mouseDown = true;
+        break;
+      case topLevelTypes.topContextMenu:
+      case topLevelTypes.topMouseUp:
+        mouseDown = false;
+        return constructSelectEvent(nativeEvent);
+
+      // Chrome and IE fire non-standard event when selection is changed (and
+      // sometimes when it hasn't).
+      // Firefox doesn't support selectionchange, so check selection status
+      // after each key entry. The selection changes after keydown and before
+      // keyup, but we check on keydown as well in the case of holding down a
+      // key, when multiple keydown events are fired but only one keyup is.
+      case topLevelTypes.topSelectionChange:
+      case topLevelTypes.topKeyDown:
+      case topLevelTypes.topKeyUp:
+        return constructSelectEvent(nativeEvent);
+    }
+  }
+};
+
+module.exports = SelectEventPlugin;
+
+},{"./EventConstants":15,"./EventPropagators":20,"./ReactInputSelection":66,"./SyntheticEvent":96,"./getActiveElement":122,"./isTextInputElement":139,"./keyOf":142,"./shallowEqual":151}],91:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ServerReactRootIndex
+ * @typechecks
+ */
+
+'use strict';
+
+/**
+ * Size of the reactRoot ID space. We generate random numbers for React root
+ * IDs and if there's a collision the events and DOM update system will
+ * get confused. In the future we need a way to generate GUIDs but for
+ * now this will work on a smaller scale.
+ */
+var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);
+
+var ServerReactRootIndex = {
+  createReactRootIndex: function() {
+    return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
+  }
+};
+
+module.exports = ServerReactRootIndex;
+
+},{}],92:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SimpleEventPlugin
+ */
+
+'use strict';
+
+var EventConstants = require("./EventConstants");
+var EventPluginUtils = require("./EventPluginUtils");
+var EventPropagators = require("./EventPropagators");
+var SyntheticClipboardEvent = require("./SyntheticClipboardEvent");
+var SyntheticEvent = require("./SyntheticEvent");
+var SyntheticFocusEvent = require("./SyntheticFocusEvent");
+var SyntheticKeyboardEvent = require("./SyntheticKeyboardEvent");
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+var SyntheticDragEvent = require("./SyntheticDragEvent");
+var SyntheticTouchEvent = require("./SyntheticTouchEvent");
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+var SyntheticWheelEvent = require("./SyntheticWheelEvent");
+
+var getEventCharCode = require("./getEventCharCode");
+
+var invariant = require("./invariant");
+var keyOf = require("./keyOf");
+var warning = require("./warning");
+
+var topLevelTypes = EventConstants.topLevelTypes;
+
+var eventTypes = {
+  blur: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onBlur: true}),
+      captured: keyOf({onBlurCapture: true})
+    }
+  },
+  click: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onClick: true}),
+      captured: keyOf({onClickCapture: true})
+    }
+  },
+  contextMenu: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onContextMenu: true}),
+      captured: keyOf({onContextMenuCapture: true})
+    }
+  },
+  copy: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCopy: true}),
+      captured: keyOf({onCopyCapture: true})
+    }
+  },
+  cut: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onCut: true}),
+      captured: keyOf({onCutCapture: true})
+    }
+  },
+  doubleClick: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDoubleClick: true}),
+      captured: keyOf({onDoubleClickCapture: true})
+    }
+  },
+  drag: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDrag: true}),
+      captured: keyOf({onDragCapture: true})
+    }
+  },
+  dragEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragEnd: true}),
+      captured: keyOf({onDragEndCapture: true})
+    }
+  },
+  dragEnter: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragEnter: true}),
+      captured: keyOf({onDragEnterCapture: true})
+    }
+  },
+  dragExit: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragExit: true}),
+      captured: keyOf({onDragExitCapture: true})
+    }
+  },
+  dragLeave: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragLeave: true}),
+      captured: keyOf({onDragLeaveCapture: true})
+    }
+  },
+  dragOver: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragOver: true}),
+      captured: keyOf({onDragOverCapture: true})
+    }
+  },
+  dragStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDragStart: true}),
+      captured: keyOf({onDragStartCapture: true})
+    }
+  },
+  drop: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onDrop: true}),
+      captured: keyOf({onDropCapture: true})
+    }
+  },
+  focus: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onFocus: true}),
+      captured: keyOf({onFocusCapture: true})
+    }
+  },
+  input: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onInput: true}),
+      captured: keyOf({onInputCapture: true})
+    }
+  },
+  keyDown: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyDown: true}),
+      captured: keyOf({onKeyDownCapture: true})
+    }
+  },
+  keyPress: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyPress: true}),
+      captured: keyOf({onKeyPressCapture: true})
+    }
+  },
+  keyUp: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onKeyUp: true}),
+      captured: keyOf({onKeyUpCapture: true})
+    }
+  },
+  load: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onLoad: true}),
+      captured: keyOf({onLoadCapture: true})
+    }
+  },
+  error: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onError: true}),
+      captured: keyOf({onErrorCapture: true})
+    }
+  },
+  // Note: We do not allow listening to mouseOver events. Instead, use the
+  // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
+  mouseDown: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseDown: true}),
+      captured: keyOf({onMouseDownCapture: true})
+    }
+  },
+  mouseMove: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseMove: true}),
+      captured: keyOf({onMouseMoveCapture: true})
+    }
+  },
+  mouseOut: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseOut: true}),
+      captured: keyOf({onMouseOutCapture: true})
+    }
+  },
+  mouseOver: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseOver: true}),
+      captured: keyOf({onMouseOverCapture: true})
+    }
+  },
+  mouseUp: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onMouseUp: true}),
+      captured: keyOf({onMouseUpCapture: true})
+    }
+  },
+  paste: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onPaste: true}),
+      captured: keyOf({onPasteCapture: true})
+    }
+  },
+  reset: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onReset: true}),
+      captured: keyOf({onResetCapture: true})
+    }
+  },
+  scroll: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onScroll: true}),
+      captured: keyOf({onScrollCapture: true})
+    }
+  },
+  submit: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onSubmit: true}),
+      captured: keyOf({onSubmitCapture: true})
+    }
+  },
+  touchCancel: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchCancel: true}),
+      captured: keyOf({onTouchCancelCapture: true})
+    }
+  },
+  touchEnd: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchEnd: true}),
+      captured: keyOf({onTouchEndCapture: true})
+    }
+  },
+  touchMove: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchMove: true}),
+      captured: keyOf({onTouchMoveCapture: true})
+    }
+  },
+  touchStart: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onTouchStart: true}),
+      captured: keyOf({onTouchStartCapture: true})
+    }
+  },
+  wheel: {
+    phasedRegistrationNames: {
+      bubbled: keyOf({onWheel: true}),
+      captured: keyOf({onWheelCapture: true})
+    }
+  }
+};
+
+var topLevelEventsToDispatchConfig = {
+  topBlur:        eventTypes.blur,
+  topClick:       eventTypes.click,
+  topContextMenu: eventTypes.contextMenu,
+  topCopy:        eventTypes.copy,
+  topCut:         eventTypes.cut,
+  topDoubleClick: eventTypes.doubleClick,
+  topDrag:        eventTypes.drag,
+  topDragEnd:     eventTypes.dragEnd,
+  topDragEnter:   eventTypes.dragEnter,
+  topDragExit:    eventTypes.dragExit,
+  topDragLeave:   eventTypes.dragLeave,
+  topDragOver:    eventTypes.dragOver,
+  topDragStart:   eventTypes.dragStart,
+  topDrop:        eventTypes.drop,
+  topError:       eventTypes.error,
+  topFocus:       eventTypes.focus,
+  topInput:       eventTypes.input,
+  topKeyDown:     eventTypes.keyDown,
+  topKeyPress:    eventTypes.keyPress,
+  topKeyUp:       eventTypes.keyUp,
+  topLoad:        eventTypes.load,
+  topMouseDown:   eventTypes.mouseDown,
+  topMouseMove:   eventTypes.mouseMove,
+  topMouseOut:    eventTypes.mouseOut,
+  topMouseOver:   eventTypes.mouseOver,
+  topMouseUp:     eventTypes.mouseUp,
+  topPaste:       eventTypes.paste,
+  topReset:       eventTypes.reset,
+  topScroll:      eventTypes.scroll,
+  topSubmit:      eventTypes.submit,
+  topTouchCancel: eventTypes.touchCancel,
+  topTouchEnd:    eventTypes.touchEnd,
+  topTouchMove:   eventTypes.touchMove,
+  topTouchStart:  eventTypes.touchStart,
+  topWheel:       eventTypes.wheel
+};
+
+for (var type in topLevelEventsToDispatchConfig) {
+  topLevelEventsToDispatchConfig[type].dependencies = [type];
+}
+
+var SimpleEventPlugin = {
+
+  eventTypes: eventTypes,
+
+  /**
+   * Same as the default implementation, except cancels the event when return
+   * value is false. This behavior will be disabled in a future release.
+   *
+   * @param {object} Event to be dispatched.
+   * @param {function} Application-level callback.
+   * @param {string} domID DOM ID to pass to the callback.
+   */
+  executeDispatch: function(event, listener, domID) {
+    var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);
+
+    ("production" !== process.env.NODE_ENV ? warning(
+      typeof returnValue !== 'boolean',
+      'Returning `false` from an event handler is deprecated and will be ' +
+      'ignored in a future release. Instead, manually call ' +
+      'e.stopPropagation() or e.preventDefault(), as appropriate.'
+    ) : null);
+
+    if (returnValue === false) {
+      event.stopPropagation();
+      event.preventDefault();
+    }
+  },
+
+  /**
+   * @param {string} topLevelType Record from `EventConstants`.
+   * @param {DOMEventTarget} topLevelTarget The listening component root node.
+   * @param {string} topLevelTargetID ID of `topLevelTarget`.
+   * @param {object} nativeEvent Native browser event.
+   * @return {*} An accumulation of synthetic events.
+   * @see {EventPluginHub.extractEvents}
+   */
+  extractEvents: function(
+      topLevelType,
+      topLevelTarget,
+      topLevelTargetID,
+      nativeEvent) {
+    var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
+    if (!dispatchConfig) {
+      return null;
+    }
+    var EventConstructor;
+    switch (topLevelType) {
+      case topLevelTypes.topInput:
+      case topLevelTypes.topLoad:
+      case topLevelTypes.topError:
+      case topLevelTypes.topReset:
+      case topLevelTypes.topSubmit:
+        // HTML Events
+        // @see http://www.w3.org/TR/html5/index.html#events-0
+        EventConstructor = SyntheticEvent;
+        break;
+      case topLevelTypes.topKeyPress:
+        // FireFox creates a keypress event for function keys too. This removes
+        // the unwanted keypress events. Enter is however both printable and
+        // non-printable. One would expect Tab to be as well (but it isn't).
+        if (getEventCharCode(nativeEvent) === 0) {
+          return null;
+        }
+        /* falls through */
+      case topLevelTypes.topKeyDown:
+      case topLevelTypes.topKeyUp:
+        EventConstructor = SyntheticKeyboardEvent;
+        break;
+      case topLevelTypes.topBlur:
+      case topLevelTypes.topFocus:
+        EventConstructor = SyntheticFocusEvent;
+        break;
+      case topLevelTypes.topClick:
+        // Firefox creates a click event on right mouse clicks. This removes the
+        // unwanted click events.
+        if (nativeEvent.button === 2) {
+          return null;
+        }
+        /* falls through */
+      case topLevelTypes.topContextMenu:
+      case topLevelTypes.topDoubleClick:
+      case topLevelTypes.topMouseDown:
+      case topLevelTypes.topMouseMove:
+      case topLevelTypes.topMouseOut:
+      case topLevelTypes.topMouseOver:
+      case topLevelTypes.topMouseUp:
+        EventConstructor = SyntheticMouseEvent;
+        break;
+      case topLevelTypes.topDrag:
+      case topLevelTypes.topDragEnd:
+      case topLevelTypes.topDragEnter:
+      case topLevelTypes.topDragExit:
+      case topLevelTypes.topDragLeave:
+      case topLevelTypes.topDragOver:
+      case topLevelTypes.topDragStart:
+      case topLevelTypes.topDrop:
+        EventConstructor = SyntheticDragEvent;
+        break;
+      case topLevelTypes.topTouchCancel:
+      case topLevelTypes.topTouchEnd:
+      case topLevelTypes.topTouchMove:
+      case topLevelTypes.topTouchStart:
+        EventConstructor = SyntheticTouchEvent;
+        break;
+      case topLevelTypes.topScroll:
+        EventConstructor = SyntheticUIEvent;
+        break;
+      case topLevelTypes.topWheel:
+        EventConstructor = SyntheticWheelEvent;
+        break;
+      case topLevelTypes.topCopy:
+      case topLevelTypes.topCut:
+      case topLevelTypes.topPaste:
+        EventConstructor = SyntheticClipboardEvent;
+        break;
+    }
+    ("production" !== process.env.NODE_ENV ? invariant(
+      EventConstructor,
+      'SimpleEventPlugin: Unhandled event type, `%s`.',
+      topLevelType
+    ) : invariant(EventConstructor));
+    var event = EventConstructor.getPooled(
+      dispatchConfig,
+      topLevelTargetID,
+      nativeEvent
+    );
+    EventPropagators.accumulateTwoPhaseDispatches(event);
+    return event;
+  }
+
+};
+
+module.exports = SimpleEventPlugin;
+
+}).call(this,require('_process'))
+},{"./EventConstants":15,"./EventPluginUtils":19,"./EventPropagators":20,"./SyntheticClipboardEvent":93,"./SyntheticDragEvent":95,"./SyntheticEvent":96,"./SyntheticFocusEvent":97,"./SyntheticKeyboardEvent":99,"./SyntheticMouseEvent":100,"./SyntheticTouchEvent":101,"./SyntheticUIEvent":102,"./SyntheticWheelEvent":103,"./getEventCharCode":123,"./invariant":136,"./keyOf":142,"./warning":155,"_process":157}],93:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticClipboardEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/clipboard-apis/
+ */
+var ClipboardEventInterface = {
+  clipboardData: function(event) {
+    return (
+      'clipboardData' in event ?
+        event.clipboardData :
+        window.clipboardData
+    );
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);
+
+module.exports = SyntheticClipboardEvent;
+
+},{"./SyntheticEvent":96}],94:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticCompositionEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
+ */
+var CompositionEventInterface = {
+  data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticCompositionEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+  SyntheticCompositionEvent,
+  CompositionEventInterface
+);
+
+module.exports = SyntheticCompositionEvent;
+
+},{"./SyntheticEvent":96}],95:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticDragEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+/**
+ * @interface DragEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var DragEventInterface = {
+  dataTransfer: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);
+
+module.exports = SyntheticDragEvent;
+
+},{"./SyntheticMouseEvent":100}],96:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var PooledClass = require("./PooledClass");
+
+var assign = require("./Object.assign");
+var emptyFunction = require("./emptyFunction");
+var getEventTarget = require("./getEventTarget");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var EventInterface = {
+  type: null,
+  target: getEventTarget,
+  // currentTarget is set when dispatching; no use in copying it here
+  currentTarget: emptyFunction.thatReturnsNull,
+  eventPhase: null,
+  bubbles: null,
+  cancelable: null,
+  timeStamp: function(event) {
+    return event.timeStamp || Date.now();
+  },
+  defaultPrevented: null,
+  isTrusted: null
+};
+
+/**
+ * Synthetic events are dispatched by event plugins, typically in response to a
+ * top-level event delegation handler.
+ *
+ * These systems should generally use pooling to reduce the frequency of garbage
+ * collection. The system should check `isPersistent` to determine whether the
+ * event should be released into the pool after being dispatched. Users that
+ * need a persisted event should invoke `persist`.
+ *
+ * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
+ * normalizing browser quirks. Subclasses do not necessarily have to implement a
+ * DOM interface; custom application-specific events can also subclass this.
+ *
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ */
+function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  this.dispatchConfig = dispatchConfig;
+  this.dispatchMarker = dispatchMarker;
+  this.nativeEvent = nativeEvent;
+
+  var Interface = this.constructor.Interface;
+  for (var propName in Interface) {
+    if (!Interface.hasOwnProperty(propName)) {
+      continue;
+    }
+    var normalize = Interface[propName];
+    if (normalize) {
+      this[propName] = normalize(nativeEvent);
+    } else {
+      this[propName] = nativeEvent[propName];
+    }
+  }
+
+  var defaultPrevented = nativeEvent.defaultPrevented != null ?
+    nativeEvent.defaultPrevented :
+    nativeEvent.returnValue === false;
+  if (defaultPrevented) {
+    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+  } else {
+    this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
+  }
+  this.isPropagationStopped = emptyFunction.thatReturnsFalse;
+}
+
+assign(SyntheticEvent.prototype, {
+
+  preventDefault: function() {
+    this.defaultPrevented = true;
+    var event = this.nativeEvent;
+    if (event.preventDefault) {
+      event.preventDefault();
+    } else {
+      event.returnValue = false;
+    }
+    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
+  },
+
+  stopPropagation: function() {
+    var event = this.nativeEvent;
+    if (event.stopPropagation) {
+      event.stopPropagation();
+    } else {
+      event.cancelBubble = true;
+    }
+    this.isPropagationStopped = emptyFunction.thatReturnsTrue;
+  },
+
+  /**
+   * We release all dispatched `SyntheticEvent`s after each event loop, adding
+   * them back into the pool. This allows a way to hold onto a reference that
+   * won't be added back into the pool.
+   */
+  persist: function() {
+    this.isPersistent = emptyFunction.thatReturnsTrue;
+  },
+
+  /**
+   * Checks if this event should be released back into the pool.
+   *
+   * @return {boolean} True if this should not be released, false otherwise.
+   */
+  isPersistent: emptyFunction.thatReturnsFalse,
+
+  /**
+   * `PooledClass` looks for `destructor` on each instance it releases.
+   */
+  destructor: function() {
+    var Interface = this.constructor.Interface;
+    for (var propName in Interface) {
+      this[propName] = null;
+    }
+    this.dispatchConfig = null;
+    this.dispatchMarker = null;
+    this.nativeEvent = null;
+  }
+
+});
+
+SyntheticEvent.Interface = EventInterface;
+
+/**
+ * Helper to reduce boilerplate when creating subclasses.
+ *
+ * @param {function} Class
+ * @param {?object} Interface
+ */
+SyntheticEvent.augmentClass = function(Class, Interface) {
+  var Super = this;
+
+  var prototype = Object.create(Super.prototype);
+  assign(prototype, Class.prototype);
+  Class.prototype = prototype;
+  Class.prototype.constructor = Class;
+
+  Class.Interface = assign({}, Super.Interface, Interface);
+  Class.augmentClass = Super.augmentClass;
+
+  PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
+};
+
+PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);
+
+module.exports = SyntheticEvent;
+
+},{"./Object.assign":27,"./PooledClass":28,"./emptyFunction":115,"./getEventTarget":126}],97:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticFocusEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+/**
+ * @interface FocusEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var FocusEventInterface = {
+  relatedTarget: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);
+
+module.exports = SyntheticFocusEvent;
+
+},{"./SyntheticUIEvent":102}],98:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticInputEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+/**
+ * @interface Event
+ * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
+ *      /#events-inputevents
+ */
+var InputEventInterface = {
+  data: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticInputEvent(
+  dispatchConfig,
+  dispatchMarker,
+  nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(
+  SyntheticInputEvent,
+  InputEventInterface
+);
+
+module.exports = SyntheticInputEvent;
+
+},{"./SyntheticEvent":96}],99:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticKeyboardEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+var getEventCharCode = require("./getEventCharCode");
+var getEventKey = require("./getEventKey");
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface KeyboardEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var KeyboardEventInterface = {
+  key: getEventKey,
+  location: null,
+  ctrlKey: null,
+  shiftKey: null,
+  altKey: null,
+  metaKey: null,
+  repeat: null,
+  locale: null,
+  getModifierState: getEventModifierState,
+  // Legacy Interface
+  charCode: function(event) {
+    // `charCode` is the result of a KeyPress event and represents the value of
+    // the actual printable character.
+
+    // KeyPress is deprecated, but its replacement is not yet final and not
+    // implemented in any major browser. Only KeyPress has charCode.
+    if (event.type === 'keypress') {
+      return getEventCharCode(event);
+    }
+    return 0;
+  },
+  keyCode: function(event) {
+    // `keyCode` is the result of a KeyDown/Up event and represents the value of
+    // physical keyboard key.
+
+    // The actual meaning of the value depends on the users' keyboard layout
+    // which cannot be detected. Assuming that it is a US keyboard layout
+    // provides a surprisingly accurate mapping for US and European users.
+    // Due to this, it is left to the user to implement at this time.
+    if (event.type === 'keydown' || event.type === 'keyup') {
+      return event.keyCode;
+    }
+    return 0;
+  },
+  which: function(event) {
+    // `which` is an alias for either `keyCode` or `charCode` depending on the
+    // type of the event.
+    if (event.type === 'keypress') {
+      return getEventCharCode(event);
+    }
+    if (event.type === 'keydown' || event.type === 'keyup') {
+      return event.keyCode;
+    }
+    return 0;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);
+
+module.exports = SyntheticKeyboardEvent;
+
+},{"./SyntheticUIEvent":102,"./getEventCharCode":123,"./getEventKey":124,"./getEventModifierState":125}],100:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticMouseEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+var ViewportMetrics = require("./ViewportMetrics");
+
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface MouseEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var MouseEventInterface = {
+  screenX: null,
+  screenY: null,
+  clientX: null,
+  clientY: null,
+  ctrlKey: null,
+  shiftKey: null,
+  altKey: null,
+  metaKey: null,
+  getModifierState: getEventModifierState,
+  button: function(event) {
+    // Webkit, Firefox, IE9+
+    // which:  1 2 3
+    // button: 0 1 2 (standard)
+    var button = event.button;
+    if ('which' in event) {
+      return button;
+    }
+    // IE<9
+    // which:  undefined
+    // button: 0 0 0
+    // button: 1 4 2 (onmouseup)
+    return button === 2 ? 2 : button === 4 ? 1 : 0;
+  },
+  buttons: null,
+  relatedTarget: function(event) {
+    return event.relatedTarget || (
+      ((event.fromElement === event.srcElement ? event.toElement : event.fromElement))
+    );
+  },
+  // "Proprietary" Interface.
+  pageX: function(event) {
+    return 'pageX' in event ?
+      event.pageX :
+      event.clientX + ViewportMetrics.currentScrollLeft;
+  },
+  pageY: function(event) {
+    return 'pageY' in event ?
+      event.pageY :
+      event.clientY + ViewportMetrics.currentScrollTop;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);
+
+module.exports = SyntheticMouseEvent;
+
+},{"./SyntheticUIEvent":102,"./ViewportMetrics":105,"./getEventModifierState":125}],101:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticTouchEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticUIEvent = require("./SyntheticUIEvent");
+
+var getEventModifierState = require("./getEventModifierState");
+
+/**
+ * @interface TouchEvent
+ * @see http://www.w3.org/TR/touch-events/
+ */
+var TouchEventInterface = {
+  touches: null,
+  targetTouches: null,
+  changedTouches: null,
+  altKey: null,
+  metaKey: null,
+  ctrlKey: null,
+  shiftKey: null,
+  getModifierState: getEventModifierState
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticUIEvent}
+ */
+function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);
+
+module.exports = SyntheticTouchEvent;
+
+},{"./SyntheticUIEvent":102,"./getEventModifierState":125}],102:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticUIEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticEvent = require("./SyntheticEvent");
+
+var getEventTarget = require("./getEventTarget");
+
+/**
+ * @interface UIEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var UIEventInterface = {
+  view: function(event) {
+    if (event.view) {
+      return event.view;
+    }
+
+    var target = getEventTarget(event);
+    if (target != null && target.window === target) {
+      // target is a window object
+      return target;
+    }
+
+    var doc = target.ownerDocument;
+    // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
+    if (doc) {
+      return doc.defaultView || doc.parentWindow;
+    } else {
+      return window;
+    }
+  },
+  detail: function(event) {
+    return event.detail || 0;
+  }
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticEvent}
+ */
+function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);
+
+module.exports = SyntheticUIEvent;
+
+},{"./SyntheticEvent":96,"./getEventTarget":126}],103:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule SyntheticWheelEvent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var SyntheticMouseEvent = require("./SyntheticMouseEvent");
+
+/**
+ * @interface WheelEvent
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/
+ */
+var WheelEventInterface = {
+  deltaX: function(event) {
+    return (
+      'deltaX' in event ? event.deltaX :
+      // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
+      'wheelDeltaX' in event ? -event.wheelDeltaX : 0
+    );
+  },
+  deltaY: function(event) {
+    return (
+      'deltaY' in event ? event.deltaY :
+      // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
+      'wheelDeltaY' in event ? -event.wheelDeltaY :
+      // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
+      'wheelDelta' in event ? -event.wheelDelta : 0
+    );
+  },
+  deltaZ: null,
+
+  // Browsers without "deltaMode" is reporting in raw wheel delta where one
+  // notch on the scroll is always +/- 120, roughly equivalent to pixels.
+  // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
+  // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
+  deltaMode: null
+};
+
+/**
+ * @param {object} dispatchConfig Configuration used to dispatch this event.
+ * @param {string} dispatchMarker Marker identifying the event target.
+ * @param {object} nativeEvent Native browser event.
+ * @extends {SyntheticMouseEvent}
+ */
+function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) {
+  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
+}
+
+SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);
+
+module.exports = SyntheticWheelEvent;
+
+},{"./SyntheticMouseEvent":100}],104:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule Transaction
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ * `Transaction` creates a black box that is able to wrap any method such that
+ * certain invariants are maintained before and after the method is invoked
+ * (Even if an exception is thrown while invoking the wrapped method). Whoever
+ * instantiates a transaction can provide enforcers of the invariants at
+ * creation time. The `Transaction` class itself will supply one additional
+ * automatic invariant for you - the invariant that any transaction instance
+ * should not be run while it is already being run. You would typically create a
+ * single instance of a `Transaction` for reuse multiple times, that potentially
+ * is used to wrap several different methods. Wrappers are extremely simple -
+ * they only require implementing two methods.
+ *
+ * <pre>
+ *                       wrappers (injected at creation time)
+ *                                      +        +
+ *                                      |        |
+ *                    +-----------------|--------|--------------+
+ *                    |                 v        |              |
+ *                    |      +---------------+   |              |
+ *                    |   +--|    wrapper1   |---|----+         |
+ *                    |   |  +---------------+   v    |         |
+ *                    |   |          +-------------+  |         |
+ *                    |   |     +----|   wrapper2  |--------+   |
+ *                    |   |     |    +-------------+  |     |   |
+ *                    |   |     |                     |     |   |
+ *                    |   v     v                     v     v   | wrapper
+ *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
+ * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+ * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | |   | |   |   |         |   |   | |   | |
+ *                    | +---+ +---+   +---------+   +---+ +---+ |
+ *                    |  initialize                    close    |
+ *                    +-----------------------------------------+
+ * </pre>
+ *
+ * Use cases:
+ * - Preserving the input selection ranges before/after reconciliation.
+ *   Restoring selection even in the event of an unexpected error.
+ * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
+ *   while guaranteeing that afterwards, the event system is reactivated.
+ * - Flushing a queue of collected DOM mutations to the main UI thread after a
+ *   reconciliation takes place in a worker thread.
+ * - Invoking any collected `componentDidUpdate` callbacks after rendering new
+ *   content.
+ * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
+ *   to preserve the `scrollTop` (an automatic scroll aware DOM).
+ * - (Future use case): Layout calculations before and after DOM updates.
+ *
+ * Transactional plugin API:
+ * - A module that has an `initialize` method that returns any precomputation.
+ * - and a `close` method that accepts the precomputation. `close` is invoked
+ *   when the wrapped process is completed, or has failed.
+ *
+ * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
+ * that implement `initialize` and `close`.
+ * @return {Transaction} Single transaction for reuse in thread.
+ *
+ * @class Transaction
+ */
+var Mixin = {
+  /**
+   * Sets up this instance so that it is prepared for collecting metrics. Does
+   * so such that this setup method may be used on an instance that is already
+   * initialized, in a way that does not consume additional memory upon reuse.
+   * That can be useful if you decide to make your subclass of this mixin a
+   * "PooledClass".
+   */
+  reinitializeTransaction: function() {
+    this.transactionWrappers = this.getTransactionWrappers();
+    if (!this.wrapperInitData) {
+      this.wrapperInitData = [];
+    } else {
+      this.wrapperInitData.length = 0;
+    }
+    this._isInTransaction = false;
+  },
+
+  _isInTransaction: false,
+
+  /**
+   * @abstract
+   * @return {Array<TransactionWrapper>} Array of transaction wrappers.
+   */
+  getTransactionWrappers: null,
+
+  isInTransaction: function() {
+    return !!this._isInTransaction;
+  },
+
+  /**
+   * Executes the function within a safety window. Use this for the top level
+   * methods that result in large amounts of computation/mutations that would
+   * need to be safety checked.
+   *
+   * @param {function} method Member of scope to call.
+   * @param {Object} scope Scope to invoke from.
+   * @param {Object?=} args... Arguments to pass to the method (optional).
+   *                           Helps prevent need to bind in many cases.
+   * @return Return value from `method`.
+   */
+  perform: function(method, scope, a, b, c, d, e, f) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      !this.isInTransaction(),
+      'Transaction.perform(...): Cannot initialize a transaction when there ' +
+      'is already an outstanding transaction.'
+    ) : invariant(!this.isInTransaction()));
+    var errorThrown;
+    var ret;
+    try {
+      this._isInTransaction = true;
+      // Catching errors makes debugging more difficult, so we start with
+      // errorThrown set to true before setting it to false after calling
+      // close -- if it's still set to true in the finally block, it means
+      // one of these calls threw.
+      errorThrown = true;
+      this.initializeAll(0);
+      ret = method.call(scope, a, b, c, d, e, f);
+      errorThrown = false;
+    } finally {
+      try {
+        if (errorThrown) {
+          // If `method` throws, prefer to show that stack trace over any thrown
+          // by invoking `closeAll`.
+          try {
+            this.closeAll(0);
+          } catch (err) {
+          }
+        } else {
+          // Since `method` didn't throw, we don't want to silence the exception
+          // here.
+          this.closeAll(0);
+        }
+      } finally {
+        this._isInTransaction = false;
+      }
+    }
+    return ret;
+  },
+
+  initializeAll: function(startIndex) {
+    var transactionWrappers = this.transactionWrappers;
+    for (var i = startIndex; i < transactionWrappers.length; i++) {
+      var wrapper = transactionWrappers[i];
+      try {
+        // Catching errors makes debugging more difficult, so we start with the
+        // OBSERVED_ERROR state before overwriting it with the real return value
+        // of initialize -- if it's still set to OBSERVED_ERROR in the finally
+        // block, it means wrapper.initialize threw.
+        this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
+        this.wrapperInitData[i] = wrapper.initialize ?
+          wrapper.initialize.call(this) :
+          null;
+      } finally {
+        if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
+          // The initializer for wrapper i threw an error; initialize the
+          // remaining wrappers but silence any exceptions from them to ensure
+          // that the first error is the one to bubble up.
+          try {
+            this.initializeAll(i + 1);
+          } catch (err) {
+          }
+        }
+      }
+    }
+  },
+
+  /**
+   * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
+   * them the respective return values of `this.transactionWrappers.init[i]`
+   * (`close`rs that correspond to initializers that failed will not be
+   * invoked).
+   */
+  closeAll: function(startIndex) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      this.isInTransaction(),
+      'Transaction.closeAll(): Cannot close transaction when none are open.'
+    ) : invariant(this.isInTransaction()));
+    var transactionWrappers = this.transactionWrappers;
+    for (var i = startIndex; i < transactionWrappers.length; i++) {
+      var wrapper = transactionWrappers[i];
+      var initData = this.wrapperInitData[i];
+      var errorThrown;
+      try {
+        // Catching errors makes debugging more difficult, so we start with
+        // errorThrown set to true before setting it to false after calling
+        // close -- if it's still set to true in the finally block, it means
+        // wrapper.close threw.
+        errorThrown = true;
+        if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) {
+          wrapper.close.call(this, initData);
+        }
+        errorThrown = false;
+      } finally {
+        if (errorThrown) {
+          // The closer for wrapper i threw an error; close the remaining
+          // wrappers but silence any exceptions from them to ensure that the
+          // first error is the one to bubble up.
+          try {
+            this.closeAll(i + 1);
+          } catch (e) {
+          }
+        }
+      }
+    }
+    this.wrapperInitData.length = 0;
+  }
+};
+
+var Transaction = {
+
+  Mixin: Mixin,
+
+  /**
+   * Token to look for to determine if an error occured.
+   */
+  OBSERVED_ERROR: {}
+
+};
+
+module.exports = Transaction;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],105:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ViewportMetrics
+ */
+
+'use strict';
+
+var ViewportMetrics = {
+
+  currentScrollLeft: 0,
+
+  currentScrollTop: 0,
+
+  refreshScrollValues: function(scrollPosition) {
+    ViewportMetrics.currentScrollLeft = scrollPosition.x;
+    ViewportMetrics.currentScrollTop = scrollPosition.y;
+  }
+
+};
+
+module.exports = ViewportMetrics;
+
+},{}],106:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule accumulateInto
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ *
+ * Accumulates items that must not be null or undefined into the first one. This
+ * is used to conserve memory by avoiding array allocations, and thus sacrifices
+ * API cleanness. Since `current` can be null before being passed in and not
+ * null after this function, make sure to assign it back to `current`:
+ *
+ * `a = accumulateInto(a, b);`
+ *
+ * This API should be sparingly used. Try `accumulate` for something cleaner.
+ *
+ * @return {*|array<*>} An accumulation of items.
+ */
+
+function accumulateInto(current, next) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    next != null,
+    'accumulateInto(...): Accumulated items must not be null or undefined.'
+  ) : invariant(next != null));
+  if (current == null) {
+    return next;
+  }
+
+  // Both are not empty. Warning: Never call x.concat(y) when you are not
+  // certain that x is an Array (x could be a string with concat method).
+  var currentIsArray = Array.isArray(current);
+  var nextIsArray = Array.isArray(next);
+
+  if (currentIsArray && nextIsArray) {
+    current.push.apply(current, next);
+    return current;
+  }
+
+  if (currentIsArray) {
+    current.push(next);
+    return current;
+  }
+
+  if (nextIsArray) {
+    // A bit too dangerous to mutate `next`.
+    return [current].concat(next);
+  }
+
+  return [current, next];
+}
+
+module.exports = accumulateInto;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],107:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule adler32
+ */
+
+/* jslint bitwise:true */
+
+'use strict';
+
+var MOD = 65521;
+
+// This is a clean-room implementation of adler32 designed for detecting
+// if markup is not what we expect it to be. It does not need to be
+// cryptographically strong, only reasonably good at detecting if markup
+// generated on the server is different than that on the client.
+function adler32(data) {
+  var a = 1;
+  var b = 0;
+  for (var i = 0; i < data.length; i++) {
+    a = (a + data.charCodeAt(i)) % MOD;
+    b = (b + a) % MOD;
+  }
+  return a | (b << 16);
+}
+
+module.exports = adler32;
+
+},{}],108:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelize
+ * @typechecks
+ */
+
+var _hyphenPattern = /-(.)/g;
+
+/**
+ * Camelcases a hyphenated string, for example:
+ *
+ *   > camelize('background-color')
+ *   < "backgroundColor"
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelize(string) {
+  return string.replace(_hyphenPattern, function(_, character) {
+    return character.toUpperCase();
+  });
+}
+
+module.exports = camelize;
+
+},{}],109:[function(require,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule camelizeStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var camelize = require("./camelize");
+
+var msPattern = /^-ms-/;
+
+/**
+ * Camelcases a hyphenated CSS property name, for example:
+ *
+ *   > camelizeStyleName('background-color')
+ *   < "backgroundColor"
+ *   > camelizeStyleName('-moz-transition')
+ *   < "MozTransition"
+ *   > camelizeStyleName('-ms-transition')
+ *   < "msTransition"
+ *
+ * As Andi Smith suggests
+ * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
+ * is converted to lowercase `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function camelizeStyleName(string) {
+  return camelize(string.replace(msPattern, 'ms-'));
+}
+
+module.exports = camelizeStyleName;
+
+},{"./camelize":108}],110:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule containsNode
+ * @typechecks
+ */
+
+var isTextNode = require("./isTextNode");
+
+/*jslint bitwise:true */
+
+/**
+ * Checks if a given DOM node contains or is another DOM node.
+ *
+ * @param {?DOMNode} outerNode Outer DOM node.
+ * @param {?DOMNode} innerNode Inner DOM node.
+ * @return {boolean} True if `outerNode` contains or is `innerNode`.
+ */
+function containsNode(outerNode, innerNode) {
+  if (!outerNode || !innerNode) {
+    return false;
+  } else if (outerNode === innerNode) {
+    return true;
+  } else if (isTextNode(outerNode)) {
+    return false;
+  } else if (isTextNode(innerNode)) {
+    return containsNode(outerNode, innerNode.parentNode);
+  } else if (outerNode.contains) {
+    return outerNode.contains(innerNode);
+  } else if (outerNode.compareDocumentPosition) {
+    return !!(outerNode.compareDocumentPosition(innerNode) & 16);
+  } else {
+    return false;
+  }
+}
+
+module.exports = containsNode;
+
+},{"./isTextNode":140}],111:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createArrayFromMixed
+ * @typechecks
+ */
+
+var toArray = require("./toArray");
+
+/**
+ * Perform a heuristic test to determine if an object is "array-like".
+ *
+ *   A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
+ *   Joshu replied: "Mu."
+ *
+ * This function determines if its argument has "array nature": it returns
+ * true if the argument is an actual array, an `arguments' object, or an
+ * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
+ *
+ * It will return false for other array-like objects like Filelist.
+ *
+ * @param {*} obj
+ * @return {boolean}
+ */
+function hasArrayNature(obj) {
+  return (
+    // not null/false
+    !!obj &&
+    // arrays are objects, NodeLists are functions in Safari
+    (typeof obj == 'object' || typeof obj == 'function') &&
+    // quacks like an array
+    ('length' in obj) &&
+    // not window
+    !('setInterval' in obj) &&
+    // no DOM node should be considered an array-like
+    // a 'select' element has 'length' and 'item' properties on IE8
+    (typeof obj.nodeType != 'number') &&
+    (
+      // a real array
+      (// HTMLCollection/NodeList
+      (Array.isArray(obj) ||
+      // arguments
+      ('callee' in obj) || 'item' in obj))
+    )
+  );
+}
+
+/**
+ * Ensure that the argument is an array by wrapping it in an array if it is not.
+ * Creates a copy of the argument if it is already an array.
+ *
+ * This is mostly useful idiomatically:
+ *
+ *   var createArrayFromMixed = require('createArrayFromMixed');
+ *
+ *   function takesOneOrMoreThings(things) {
+ *     things = createArrayFromMixed(things);
+ *     ...
+ *   }
+ *
+ * This allows you to treat `things' as an array, but accept scalars in the API.
+ *
+ * If you need to convert an array-like object, like `arguments`, into an array
+ * use toArray instead.
+ *
+ * @param {*} obj
+ * @return {array}
+ */
+function createArrayFromMixed(obj) {
+  if (!hasArrayNature(obj)) {
+    return [obj];
+  } else if (Array.isArray(obj)) {
+    return obj.slice();
+  } else {
+    return toArray(obj);
+  }
+}
+
+module.exports = createArrayFromMixed;
+
+},{"./toArray":153}],112:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createFullPageComponent
+ * @typechecks
+ */
+
+'use strict';
+
+// Defeat circular references by requiring this directly.
+var ReactClass = require("./ReactClass");
+var ReactElement = require("./ReactElement");
+
+var invariant = require("./invariant");
+
+/**
+ * Create a component that will throw an exception when unmounted.
+ *
+ * Components like <html> <head> and <body> can't be removed or added
+ * easily in a cross-browser way, however it's valuable to be able to
+ * take advantage of React's reconciliation for styling and <title>
+ * management. So we just document it and throw in dangerous cases.
+ *
+ * @param {string} tag The tag to wrap
+ * @return {function} convenience constructor of new component
+ */
+function createFullPageComponent(tag) {
+  var elementFactory = ReactElement.createFactory(tag);
+
+  var FullPageComponent = ReactClass.createClass({
+    tagName: tag.toUpperCase(),
+    displayName: 'ReactFullPageComponent' + tag,
+
+    componentWillUnmount: function() {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        false,
+        '%s tried to unmount. Because of cross-browser quirks it is ' +
+        'impossible to unmount some top-level components (eg <html>, <head>, ' +
+        'and <body>) reliably and efficiently. To fix this, have a single ' +
+        'top-level component that never unmounts render these elements.',
+        this.constructor.displayName
+      ) : invariant(false));
+    },
+
+    render: function() {
+      return elementFactory(this.props);
+    }
+  });
+
+  return FullPageComponent;
+}
+
+module.exports = createFullPageComponent;
+
+}).call(this,require('_process'))
+},{"./ReactClass":34,"./ReactElement":58,"./invariant":136,"_process":157}],113:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule createNodesFromMarkup
+ * @typechecks
+ */
+
+/*jslint evil: true, sub: true */
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var createArrayFromMixed = require("./createArrayFromMixed");
+var getMarkupWrap = require("./getMarkupWrap");
+var invariant = require("./invariant");
+
+/**
+ * Dummy container used to render all markup.
+ */
+var dummyNode =
+  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Pattern used by `getNodeName`.
+ */
+var nodeNamePattern = /^\s*<(\w+)/;
+
+/**
+ * Extracts the `nodeName` of the first element in a string of markup.
+ *
+ * @param {string} markup String of markup.
+ * @return {?string} Node name of the supplied markup.
+ */
+function getNodeName(markup) {
+  var nodeNameMatch = markup.match(nodeNamePattern);
+  return nodeNameMatch && nodeNameMatch[1].toLowerCase();
+}
+
+/**
+ * Creates an array containing the nodes rendered from the supplied markup. The
+ * optionally supplied `handleScript` function will be invoked once for each
+ * <script> element that is rendered. If no `handleScript` function is supplied,
+ * an exception is thrown if any <script> elements are rendered.
+ *
+ * @param {string} markup A string of valid HTML markup.
+ * @param {?function} handleScript Invoked once for each rendered <script>.
+ * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
+ */
+function createNodesFromMarkup(markup, handleScript) {
+  var node = dummyNode;
+  ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode));
+  var nodeName = getNodeName(markup);
+
+  var wrap = nodeName && getMarkupWrap(nodeName);
+  if (wrap) {
+    node.innerHTML = wrap[1] + markup + wrap[2];
+
+    var wrapDepth = wrap[0];
+    while (wrapDepth--) {
+      node = node.lastChild;
+    }
+  } else {
+    node.innerHTML = markup;
+  }
+
+  var scripts = node.getElementsByTagName('script');
+  if (scripts.length) {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      handleScript,
+      'createNodesFromMarkup(...): Unexpected <script> element rendered.'
+    ) : invariant(handleScript));
+    createArrayFromMixed(scripts).forEach(handleScript);
+  }
+
+  var nodes = createArrayFromMixed(node.childNodes);
+  while (node.lastChild) {
+    node.removeChild(node.lastChild);
+  }
+  return nodes;
+}
+
+module.exports = createNodesFromMarkup;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":21,"./createArrayFromMixed":111,"./getMarkupWrap":128,"./invariant":136,"_process":157}],114:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule dangerousStyleValue
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var CSSProperty = require("./CSSProperty");
+
+var isUnitlessNumber = CSSProperty.isUnitlessNumber;
+
+/**
+ * Convert a value into the proper css writable value. The style name `name`
+ * should be logical (no hyphens), as specified
+ * in `CSSProperty.isUnitlessNumber`.
+ *
+ * @param {string} name CSS property name such as `topMargin`.
+ * @param {*} value CSS property value such as `10px`.
+ * @return {string} Normalized style value with dimensions applied.
+ */
+function dangerousStyleValue(name, value) {
+  // Note that we've removed escapeTextForBrowser() calls here since the
+  // whole string will be escaped when the attribute is injected into
+  // the markup. If you provide unsafe user data here they can inject
+  // arbitrary CSS which may be problematic (I couldn't repro this):
+  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
+  // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
+  // This is not an XSS hole but instead a potential CSS injection issue
+  // which has lead to a greater discussion about how we're going to
+  // trust URLs moving forward. See #2115901
+
+  var isEmpty = value == null || typeof value === 'boolean' || value === '';
+  if (isEmpty) {
+    return '';
+  }
+
+  var isNonNumeric = isNaN(value);
+  if (isNonNumeric || value === 0 ||
+      isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
+    return '' + value; // cast to string
+  }
+
+  if (typeof value === 'string') {
+    value = value.trim();
+  }
+  return value + 'px';
+}
+
+module.exports = dangerousStyleValue;
+
+},{"./CSSProperty":4}],115:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyFunction
+ */
+
+function makeEmptyFunction(arg) {
+  return function() {
+    return arg;
+  };
+}
+
+/**
+ * This function accepts and discards inputs; it has no side effects. This is
+ * primarily useful idiomatically for overridable function endpoints which
+ * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
+ */
+function emptyFunction() {}
+
+emptyFunction.thatReturns = makeEmptyFunction;
+emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
+emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
+emptyFunction.thatReturnsNull = makeEmptyFunction(null);
+emptyFunction.thatReturnsThis = function() { return this; };
+emptyFunction.thatReturnsArgument = function(arg) { return arg; };
+
+module.exports = emptyFunction;
+
+},{}],116:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyObject
+ */
+
+"use strict";
+
+var emptyObject = {};
+
+if ("production" !== process.env.NODE_ENV) {
+  Object.freeze(emptyObject);
+}
+
+module.exports = emptyObject;
+
+}).call(this,require('_process'))
+},{"_process":157}],117:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule escapeTextContentForBrowser
+ */
+
+'use strict';
+
+var ESCAPE_LOOKUP = {
+  '&': '&',
+  '>': '>',
+  '<': '<',
+  '"': '"',
+  '\'': '&#x27;'
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+  return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escapeTextContentForBrowser(text) {
+  return ('' + text).replace(ESCAPE_REGEX, escaper);
+}
+
+module.exports = escapeTextContentForBrowser;
+
+},{}],118:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule findDOMNode
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactCurrentOwner = require("./ReactCurrentOwner");
+var ReactInstanceMap = require("./ReactInstanceMap");
+var ReactMount = require("./ReactMount");
+
+var invariant = require("./invariant");
+var isNode = require("./isNode");
+var warning = require("./warning");
+
+/**
+ * Returns the DOM node rendered by this element.
+ *
+ * @param {ReactComponent|DOMElement} componentOrElement
+ * @return {DOMElement} The root node of this element.
+ */
+function findDOMNode(componentOrElement) {
+  if ("production" !== process.env.NODE_ENV) {
+    var owner = ReactCurrentOwner.current;
+    if (owner !== null) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        owner._warnedAboutRefsInRender,
+        '%s is accessing getDOMNode or findDOMNode inside its render(). ' +
+        'render() should be a pure function of props and state. It should ' +
+        'never access something that requires stale data from the previous ' +
+        'render, such as refs. Move this logic to componentDidMount and ' +
+        'componentDidUpdate instead.',
+        owner.getName() || 'A component'
+      ) : null);
+      owner._warnedAboutRefsInRender = true;
+    }
+  }
+  if (componentOrElement == null) {
+    return null;
+  }
+  if (isNode(componentOrElement)) {
+    return componentOrElement;
+  }
+  if (ReactInstanceMap.has(componentOrElement)) {
+    return ReactMount.getNodeFromInstance(componentOrElement);
+  }
+  ("production" !== process.env.NODE_ENV ? invariant(
+    componentOrElement.render == null ||
+    typeof componentOrElement.render !== 'function',
+    'Component (with keys: %s) contains `render` method ' +
+    'but is not mounted in the DOM',
+    Object.keys(componentOrElement)
+  ) : invariant(componentOrElement.render == null ||
+  typeof componentOrElement.render !== 'function'));
+  ("production" !== process.env.NODE_ENV ? invariant(
+    false,
+    'Element appears to be neither ReactComponent nor DOMNode (keys: %s)',
+    Object.keys(componentOrElement)
+  ) : invariant(false));
+}
+
+module.exports = findDOMNode;
+
+}).call(this,require('_process'))
+},{"./ReactCurrentOwner":40,"./ReactInstanceMap":68,"./ReactMount":71,"./invariant":136,"./isNode":138,"./warning":155,"_process":157}],119:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule flattenChildren
+ */
+
+'use strict';
+
+var traverseAllChildren = require("./traverseAllChildren");
+var warning = require("./warning");
+
+/**
+ * @param {function} traverseContext Context passed through traversal.
+ * @param {?ReactComponent} child React child component.
+ * @param {!string} name String name of key path to child.
+ */
+function flattenSingleChildIntoContext(traverseContext, child, name) {
+  // We found a component instance.
+  var result = traverseContext;
+  var keyUnique = !result.hasOwnProperty(name);
+  if ("production" !== process.env.NODE_ENV) {
+    ("production" !== process.env.NODE_ENV ? warning(
+      keyUnique,
+      'flattenChildren(...): Encountered two children with the same key, ' +
+      '`%s`. Child keys must be unique; when two children share a key, only ' +
+      'the first child will be used.',
+      name
+    ) : null);
+  }
+  if (keyUnique && child != null) {
+    result[name] = child;
+  }
+}
+
+/**
+ * Flattens children that are typically specified as `props.children`. Any null
+ * children will not be included in the resulting object.
+ * @return {!object} flattened children keyed by name.
+ */
+function flattenChildren(children) {
+  if (children == null) {
+    return children;
+  }
+  var result = {};
+  traverseAllChildren(children, flattenSingleChildIntoContext, result);
+  return result;
+}
+
+module.exports = flattenChildren;
+
+}).call(this,require('_process'))
+},{"./traverseAllChildren":154,"./warning":155,"_process":157}],120:[function(require,module,exports){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule focusNode
+ */
+
+"use strict";
+
+/**
+ * @param {DOMElement} node input/textarea to focus
+ */
+function focusNode(node) {
+  // IE8 can throw "Can't move focus to the control because it is invisible,
+  // not enabled, or of a type that does not accept the focus." for all kinds of
+  // reasons that are too expensive and fragile to test.
+  try {
+    node.focus();
+  } catch(e) {
+  }
+}
+
+module.exports = focusNode;
+
+},{}],121:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule forEachAccumulated
+ */
+
+'use strict';
+
+/**
+ * @param {array} an "accumulation" of items which is either an Array or
+ * a single item. Useful when paired with the `accumulate` module. This is a
+ * simple utility that allows us to reason about a collection of items, but
+ * handling the case when there is exactly one item (and we do not need to
+ * allocate an array).
+ */
+var forEachAccumulated = function(arr, cb, scope) {
+  if (Array.isArray(arr)) {
+    arr.forEach(cb, scope);
+  } else if (arr) {
+    cb.call(scope, arr);
+  }
+};
+
+module.exports = forEachAccumulated;
+
+},{}],122:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getActiveElement
+ * @typechecks
+ */
+
+/**
+ * Same as document.activeElement but wraps in a try-catch block. In IE it is
+ * not safe to call document.activeElement if there is nothing focused.
+ *
+ * The activeElement will be null only if the document body is not yet defined.
+ */
+function getActiveElement() /*?DOMElement*/ {
+  try {
+    return document.activeElement || document.body;
+  } catch (e) {
+    return document.body;
+  }
+}
+
+module.exports = getActiveElement;
+
+},{}],123:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventCharCode
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * `charCode` represents the actual "character code" and is safe to use with
+ * `String.fromCharCode`. As such, only keys that correspond to printable
+ * characters produce a valid `charCode`, the only exception to this is Enter.
+ * The Tab-key is considered non-printable and does not have a `charCode`,
+ * presumably because it does not produce a tab-character in browsers.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `charCode` property.
+ */
+function getEventCharCode(nativeEvent) {
+  var charCode;
+  var keyCode = nativeEvent.keyCode;
+
+  if ('charCode' in nativeEvent) {
+    charCode = nativeEvent.charCode;
+
+    // FF does not set `charCode` for the Enter-key, check against `keyCode`.
+    if (charCode === 0 && keyCode === 13) {
+      charCode = 13;
+    }
+  } else {
+    // IE8 does not implement `charCode`, but `keyCode` has the correct value.
+    charCode = keyCode;
+  }
+
+  // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
+  // Must not discard the (non-)printable Enter-key.
+  if (charCode >= 32 || charCode === 13) {
+    return charCode;
+  }
+
+  return 0;
+}
+
+module.exports = getEventCharCode;
+
+},{}],124:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventKey
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var getEventCharCode = require("./getEventCharCode");
+
+/**
+ * Normalization of deprecated HTML5 `key` values
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var normalizeKey = {
+  'Esc': 'Escape',
+  'Spacebar': ' ',
+  'Left': 'ArrowLeft',
+  'Up': 'ArrowUp',
+  'Right': 'ArrowRight',
+  'Down': 'ArrowDown',
+  'Del': 'Delete',
+  'Win': 'OS',
+  'Menu': 'ContextMenu',
+  'Apps': 'ContextMenu',
+  'Scroll': 'ScrollLock',
+  'MozPrintableKey': 'Unidentified'
+};
+
+/**
+ * Translation from legacy `keyCode` to HTML5 `key`
+ * Only special keys supported, all others depend on keyboard layout or browser
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
+ */
+var translateToKey = {
+  8: 'Backspace',
+  9: 'Tab',
+  12: 'Clear',
+  13: 'Enter',
+  16: 'Shift',
+  17: 'Control',
+  18: 'Alt',
+  19: 'Pause',
+  20: 'CapsLock',
+  27: 'Escape',
+  32: ' ',
+  33: 'PageUp',
+  34: 'PageDown',
+  35: 'End',
+  36: 'Home',
+  37: 'ArrowLeft',
+  38: 'ArrowUp',
+  39: 'ArrowRight',
+  40: 'ArrowDown',
+  45: 'Insert',
+  46: 'Delete',
+  112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6',
+  118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
+  144: 'NumLock',
+  145: 'ScrollLock',
+  224: 'Meta'
+};
+
+/**
+ * @param {object} nativeEvent Native browser event.
+ * @return {string} Normalized `key` property.
+ */
+function getEventKey(nativeEvent) {
+  if (nativeEvent.key) {
+    // Normalize inconsistent values reported by browsers due to
+    // implementations of a working draft specification.
+
+    // FireFox implements `key` but returns `MozPrintableKey` for all
+    // printable characters (normalized to `Unidentified`), ignore it.
+    var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
+    if (key !== 'Unidentified') {
+      return key;
+    }
+  }
+
+  // Browser does not implement `key`, polyfill as much of it as we can.
+  if (nativeEvent.type === 'keypress') {
+    var charCode = getEventCharCode(nativeEvent);
+
+    // The enter-key is technically both printable and non-printable and can
+    // thus be captured by `keypress`, no other non-printable key should.
+    return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
+  }
+  if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
+    // While user keyboard layout determines the actual meaning of each
+    // `keyCode` value, almost all function keys have a universal value.
+    return translateToKey[nativeEvent.keyCode] || 'Unidentified';
+  }
+  return '';
+}
+
+module.exports = getEventKey;
+
+},{"./getEventCharCode":123}],125:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventModifierState
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Translation from modifier key to the associated property in the event.
+ * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
+ */
+
+var modifierKeyToProp = {
+  'Alt': 'altKey',
+  'Control': 'ctrlKey',
+  'Meta': 'metaKey',
+  'Shift': 'shiftKey'
+};
+
+// IE8 does not implement getModifierState so we simply map it to the only
+// modifier keys exposed by the event itself, does not support Lock-keys.
+// Currently, all major browsers except Chrome seems to support Lock-keys.
+function modifierStateGetter(keyArg) {
+  /*jshint validthis:true */
+  var syntheticEvent = this;
+  var nativeEvent = syntheticEvent.nativeEvent;
+  if (nativeEvent.getModifierState) {
+    return nativeEvent.getModifierState(keyArg);
+  }
+  var keyProp = modifierKeyToProp[keyArg];
+  return keyProp ? !!nativeEvent[keyProp] : false;
+}
+
+function getEventModifierState(nativeEvent) {
+  return modifierStateGetter;
+}
+
+module.exports = getEventModifierState;
+
+},{}],126:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getEventTarget
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Gets the target node from a native browser event by accounting for
+ * inconsistencies in browser DOM APIs.
+ *
+ * @param {object} nativeEvent Native browser event.
+ * @return {DOMEventTarget} Target node.
+ */
+function getEventTarget(nativeEvent) {
+  var target = nativeEvent.target || nativeEvent.srcElement || window;
+  // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
+  // @see http://www.quirksmode.org/js/events_properties.html
+  return target.nodeType === 3 ? target.parentNode : target;
+}
+
+module.exports = getEventTarget;
+
+},{}],127:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getIteratorFn
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/* global Symbol */
+var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
+var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
+
+/**
+ * Returns the iterator method function contained on the iterable object.
+ *
+ * Be sure to invoke the function with the iterable as context:
+ *
+ *     var iteratorFn = getIteratorFn(myIterable);
+ *     if (iteratorFn) {
+ *       var iterator = iteratorFn.call(myIterable);
+ *       ...
+ *     }
+ *
+ * @param {?object} maybeIterable
+ * @return {?function}
+ */
+function getIteratorFn(maybeIterable) {
+  var iteratorFn = maybeIterable && (
+    (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL])
+  );
+  if (typeof iteratorFn === 'function') {
+    return iteratorFn;
+  }
+}
+
+module.exports = getIteratorFn;
+
+},{}],128:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getMarkupWrap
+ */
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var invariant = require("./invariant");
+
+/**
+ * Dummy container used to detect which wraps are necessary.
+ */
+var dummyNode =
+  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;
+
+/**
+ * Some browsers cannot use `innerHTML` to render certain elements standalone,
+ * so we wrap them, render the wrapped nodes, then extract the desired node.
+ *
+ * In IE8, certain elements cannot render alone, so wrap all elements ('*').
+ */
+var shouldWrap = {
+  // Force wrapping for SVG elements because if they get created inside a <div>,
+  // they will be initialized in the wrong namespace (and will not display).
+  'circle': true,
+  'defs': true,
+  'ellipse': true,
+  'g': true,
+  'line': true,
+  'linearGradient': true,
+  'path': true,
+  'polygon': true,
+  'polyline': true,
+  'radialGradient': true,
+  'rect': true,
+  'stop': true,
+  'text': true
+};
+
+var selectWrap = [1, '<select multiple="true">', '</select>'];
+var tableWrap = [1, '<table>', '</table>'];
+var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
+
+var svgWrap = [1, '<svg>', '</svg>'];
+
+var markupWrap = {
+  '*': [1, '?<div>', '</div>'],
+
+  'area': [1, '<map>', '</map>'],
+  'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
+  'legend': [1, '<fieldset>', '</fieldset>'],
+  'param': [1, '<object>', '</object>'],
+  'tr': [2, '<table><tbody>', '</tbody></table>'],
+
+  'optgroup': selectWrap,
+  'option': selectWrap,
+
+  'caption': tableWrap,
+  'colgroup': tableWrap,
+  'tbody': tableWrap,
+  'tfoot': tableWrap,
+  'thead': tableWrap,
+
+  'td': trWrap,
+  'th': trWrap,
+
+  'circle': svgWrap,
+  'defs': svgWrap,
+  'ellipse': svgWrap,
+  'g': svgWrap,
+  'line': svgWrap,
+  'linearGradient': svgWrap,
+  'path': svgWrap,
+  'polygon': svgWrap,
+  'polyline': svgWrap,
+  'radialGradient': svgWrap,
+  'rect': svgWrap,
+  'stop': svgWrap,
+  'text': svgWrap
+};
+
+/**
+ * Gets the markup wrap configuration for the supplied `nodeName`.
+ *
+ * NOTE: This lazily detects which wraps are necessary for the current browser.
+ *
+ * @param {string} nodeName Lowercase `nodeName`.
+ * @return {?array} Markup wrap configuration, if applicable.
+ */
+function getMarkupWrap(nodeName) {
+  ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode));
+  if (!markupWrap.hasOwnProperty(nodeName)) {
+    nodeName = '*';
+  }
+  if (!shouldWrap.hasOwnProperty(nodeName)) {
+    if (nodeName === '*') {
+      dummyNode.innerHTML = '<link />';
+    } else {
+      dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
+    }
+    shouldWrap[nodeName] = !dummyNode.firstChild;
+  }
+  return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
+}
+
+
+module.exports = getMarkupWrap;
+
+}).call(this,require('_process'))
+},{"./ExecutionEnvironment":21,"./invariant":136,"_process":157}],129:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getNodeForCharacterOffset
+ */
+
+'use strict';
+
+/**
+ * Given any node return the first leaf node without children.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {DOMElement|DOMTextNode}
+ */
+function getLeafNode(node) {
+  while (node && node.firstChild) {
+    node = node.firstChild;
+  }
+  return node;
+}
+
+/**
+ * Get the next sibling within a container. This will walk up the
+ * DOM if a node's siblings have been exhausted.
+ *
+ * @param {DOMElement|DOMTextNode} node
+ * @return {?DOMElement|DOMTextNode}
+ */
+function getSiblingNode(node) {
+  while (node) {
+    if (node.nextSibling) {
+      return node.nextSibling;
+    }
+    node = node.parentNode;
+  }
+}
+
+/**
+ * Get object describing the nodes which contain characters at offset.
+ *
+ * @param {DOMElement|DOMTextNode} root
+ * @param {number} offset
+ * @return {?object}
+ */
+function getNodeForCharacterOffset(root, offset) {
+  var node = getLeafNode(root);
+  var nodeStart = 0;
+  var nodeEnd = 0;
+
+  while (node) {
+    if (node.nodeType === 3) {
+      nodeEnd = nodeStart + node.textContent.length;
+
+      if (nodeStart <= offset && nodeEnd >= offset) {
+        return {
+          node: node,
+          offset: offset - nodeStart
+        };
+      }
+
+      nodeStart = nodeEnd;
+    }
+
+    node = getLeafNode(getSiblingNode(node));
+  }
+}
+
+module.exports = getNodeForCharacterOffset;
+
+},{}],130:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getReactRootElementInContainer
+ */
+
+'use strict';
+
+var DOC_NODE_TYPE = 9;
+
+/**
+ * @param {DOMElement|DOMDocument} container DOM element that may contain
+ *                                           a React component
+ * @return {?*} DOM element that may have the reactRoot ID, or null.
+ */
+function getReactRootElementInContainer(container) {
+  if (!container) {
+    return null;
+  }
+
+  if (container.nodeType === DOC_NODE_TYPE) {
+    return container.documentElement;
+  } else {
+    return container.firstChild;
+  }
+}
+
+module.exports = getReactRootElementInContainer;
+
+},{}],131:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getTextContentAccessor
+ */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var contentKey = null;
+
+/**
+ * Gets the key used to access text content on a DOM node.
+ *
+ * @return {?string} Key used to access text content.
+ * @internal
+ */
+function getTextContentAccessor() {
+  if (!contentKey && ExecutionEnvironment.canUseDOM) {
+    // Prefer textContent to innerText because many browsers support both but
+    // SVG <text> elements don't support innerText even when <div> does.
+    contentKey = 'textContent' in document.documentElement ?
+      'textContent' :
+      'innerText';
+  }
+  return contentKey;
+}
+
+module.exports = getTextContentAccessor;
+
+},{"./ExecutionEnvironment":21}],132:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getUnboundedScrollPosition
+ * @typechecks
+ */
+
+"use strict";
+
+/**
+ * Gets the scroll position of the supplied element or window.
+ *
+ * The return values are unbounded, unlike `getScrollPosition`. This means they
+ * may be negative or exceed the element boundaries (which is possible using
+ * inertial scrolling).
+ *
+ * @param {DOMWindow|DOMElement} scrollable
+ * @return {object} Map with `x` and `y` keys.
+ */
+function getUnboundedScrollPosition(scrollable) {
+  if (scrollable === window) {
+    return {
+      x: window.pageXOffset || document.documentElement.scrollLeft,
+      y: window.pageYOffset || document.documentElement.scrollTop
+    };
+  }
+  return {
+    x: scrollable.scrollLeft,
+    y: scrollable.scrollTop
+  };
+}
+
+module.exports = getUnboundedScrollPosition;
+
+},{}],133:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenate
+ * @typechecks
+ */
+
+var _uppercasePattern = /([A-Z])/g;
+
+/**
+ * Hyphenates a camelcased string, for example:
+ *
+ *   > hyphenate('backgroundColor')
+ *   < "background-color"
+ *
+ * For CSS style names, use `hyphenateStyleName` instead which works properly
+ * with all vendor prefixes, including `ms`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenate(string) {
+  return string.replace(_uppercasePattern, '-$1').toLowerCase();
+}
+
+module.exports = hyphenate;
+
+},{}],134:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule hyphenateStyleName
+ * @typechecks
+ */
+
+"use strict";
+
+var hyphenate = require("./hyphenate");
+
+var msPattern = /^ms-/;
+
+/**
+ * Hyphenates a camelcased CSS property name, for example:
+ *
+ *   > hyphenateStyleName('backgroundColor')
+ *   < "background-color"
+ *   > hyphenateStyleName('MozTransition')
+ *   < "-moz-transition"
+ *   > hyphenateStyleName('msTransition')
+ *   < "-ms-transition"
+ *
+ * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
+ * is converted to `-ms-`.
+ *
+ * @param {string} string
+ * @return {string}
+ */
+function hyphenateStyleName(string) {
+  return hyphenate(string).replace(msPattern, '-ms-');
+}
+
+module.exports = hyphenateStyleName;
+
+},{"./hyphenate":133}],135:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule instantiateReactComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var ReactCompositeComponent = require("./ReactCompositeComponent");
+var ReactEmptyComponent = require("./ReactEmptyComponent");
+var ReactNativeComponent = require("./ReactNativeComponent");
+
+var assign = require("./Object.assign");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+// To avoid a cyclic dependency, we create the final class in this module
+var ReactCompositeComponentWrapper = function() { };
+assign(
+  ReactCompositeComponentWrapper.prototype,
+  ReactCompositeComponent.Mixin,
+  {
+    _instantiateReactComponent: instantiateReactComponent
+  }
+);
+
+/**
+ * Check if the type reference is a known internal type. I.e. not a user
+ * provided composite type.
+ *
+ * @param {function} type
+ * @return {boolean} Returns true if this is a valid internal type.
+ */
+function isInternalComponentType(type) {
+  return (
+    typeof type === 'function' &&
+    typeof type.prototype.mountComponent === 'function' &&
+    typeof type.prototype.receiveComponent === 'function'
+  );
+}
+
+/**
+ * Given a ReactNode, create an instance that will actually be mounted.
+ *
+ * @param {ReactNode} node
+ * @param {*} parentCompositeType The composite type that resolved this.
+ * @return {object} A new instance of the element's constructor.
+ * @protected
+ */
+function instantiateReactComponent(node, parentCompositeType) {
+  var instance;
+
+  if (node === null || node === false) {
+    node = ReactEmptyComponent.emptyElement;
+  }
+
+  if (typeof node === 'object') {
+    var element = node;
+    if ("production" !== process.env.NODE_ENV) {
+      ("production" !== process.env.NODE_ENV ? warning(
+        element && (typeof element.type === 'function' ||
+                    typeof element.type === 'string'),
+        'Only functions or strings can be mounted as React components.'
+      ) : null);
+    }
+
+    // Special case string values
+    if (parentCompositeType === element.type &&
+        typeof element.type === 'string') {
+      // Avoid recursion if the wrapper renders itself.
+      instance = ReactNativeComponent.createInternalComponent(element);
+      // All native components are currently wrapped in a composite so we're
+      // safe to assume that this is what we should instantiate.
+    } else if (isInternalComponentType(element.type)) {
+      // This is temporarily available for custom components that are not string
+      // represenations. I.e. ART. Once those are updated to use the string
+      // representation, we can drop this code path.
+      instance = new element.type(element);
+    } else {
+      instance = new ReactCompositeComponentWrapper();
+    }
+  } else if (typeof node === 'string' || typeof node === 'number') {
+    instance = ReactNativeComponent.createInstanceForText(node);
+  } else {
+    ("production" !== process.env.NODE_ENV ? invariant(
+      false,
+      'Encountered invalid React node of type %s',
+      typeof node
+    ) : invariant(false));
+  }
+
+  if ("production" !== process.env.NODE_ENV) {
+    ("production" !== process.env.NODE_ENV ? warning(
+      typeof instance.construct === 'function' &&
+      typeof instance.mountComponent === 'function' &&
+      typeof instance.receiveComponent === 'function' &&
+      typeof instance.unmountComponent === 'function',
+      'Only React Components can be mounted.'
+    ) : null);
+  }
+
+  // Sets up the instance. This can probably just move into the constructor now.
+  instance.construct(node);
+
+  // These two fields are used by the DOM and ART diffing algorithms
+  // respectively. Instead of using expandos on components, we should be
+  // storing the state needed by the diffing algorithms elsewhere.
+  instance._mountIndex = 0;
+  instance._mountImage = null;
+
+  if ("production" !== process.env.NODE_ENV) {
+    instance._isOwnerNecessary = false;
+    instance._warnedAboutRefsInRender = false;
+  }
+
+  // Internal instances should fully constructed at this point, so they should
+  // not get any new fields added to them at this point.
+  if ("production" !== process.env.NODE_ENV) {
+    if (Object.preventExtensions) {
+      Object.preventExtensions(instance);
+    }
+  }
+
+  return instance;
+}
+
+module.exports = instantiateReactComponent;
+
+}).call(this,require('_process'))
+},{"./Object.assign":27,"./ReactCompositeComponent":38,"./ReactEmptyComponent":60,"./ReactNativeComponent":74,"./invariant":136,"./warning":155,"_process":157}],136:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule invariant
+ */
+
+"use strict";
+
+/**
+ * Use invariant() to assert state which your program assumes to be true.
+ *
+ * Provide sprintf-style format (only %s is supported) and arguments
+ * to provide information about what broke and what you were
+ * expecting.
+ *
+ * The invariant message will be stripped in production, but the invariant
+ * will remain to ensure logic does not differ in production.
+ */
+
+var invariant = function(condition, format, a, b, c, d, e, f) {
+  if ("production" !== process.env.NODE_ENV) {
+    if (format === undefined) {
+      throw new Error('invariant requires an error message argument');
+    }
+  }
+
+  if (!condition) {
+    var error;
+    if (format === undefined) {
+      error = new Error(
+        'Minified exception occurred; use the non-minified dev environment ' +
+        'for the full error message and additional helpful warnings.'
+      );
+    } else {
+      var args = [a, b, c, d, e, f];
+      var argIndex = 0;
+      error = new Error(
+        'Invariant Violation: ' +
+        format.replace(/%s/g, function() { return args[argIndex++]; })
+      );
+    }
+
+    error.framesToPop = 1; // we don't care about invariant's own frame
+    throw error;
+  }
+};
+
+module.exports = invariant;
+
+}).call(this,require('_process'))
+},{"_process":157}],137:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isEventSupported
+ */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var useHasFeature;
+if (ExecutionEnvironment.canUseDOM) {
+  useHasFeature =
+    document.implementation &&
+    document.implementation.hasFeature &&
+    // always returns true in newer browsers as per the standard.
+    // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
+    document.implementation.hasFeature('', '') !== true;
+}
+
+/**
+ * Checks if an event is supported in the current execution environment.
+ *
+ * NOTE: This will not work correctly for non-generic events such as `change`,
+ * `reset`, `load`, `error`, and `select`.
+ *
+ * Borrows from Modernizr.
+ *
+ * @param {string} eventNameSuffix Event name, e.g. "click".
+ * @param {?boolean} capture Check if the capture phase is supported.
+ * @return {boolean} True if the event is supported.
+ * @internal
+ * @license Modernizr 3.0.0pre (Custom Build) | MIT
+ */
+function isEventSupported(eventNameSuffix, capture) {
+  if (!ExecutionEnvironment.canUseDOM ||
+      capture && !('addEventListener' in document)) {
+    return false;
+  }
+
+  var eventName = 'on' + eventNameSuffix;
+  var isSupported = eventName in document;
+
+  if (!isSupported) {
+    var element = document.createElement('div');
+    element.setAttribute(eventName, 'return;');
+    isSupported = typeof element[eventName] === 'function';
+  }
+
+  if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
+    // This is the only way to test support for the `wheel` event in IE9+.
+    isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
+  }
+
+  return isSupported;
+}
+
+module.exports = isEventSupported;
+
+},{"./ExecutionEnvironment":21}],138:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isNode
+ * @typechecks
+ */
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM node.
+ */
+function isNode(object) {
+  return !!(object && (
+    ((typeof Node === 'function' ? object instanceof Node : typeof object === 'object' &&
+    typeof object.nodeType === 'number' &&
+    typeof object.nodeName === 'string'))
+  ));
+}
+
+module.exports = isNode;
+
+},{}],139:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextInputElement
+ */
+
+'use strict';
+
+/**
+ * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+ */
+var supportedInputTypes = {
+  'color': true,
+  'date': true,
+  'datetime': true,
+  'datetime-local': true,
+  'email': true,
+  'month': true,
+  'number': true,
+  'password': true,
+  'range': true,
+  'search': true,
+  'tel': true,
+  'text': true,
+  'time': true,
+  'url': true,
+  'week': true
+};
+
+function isTextInputElement(elem) {
+  return elem && (
+    (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type] || elem.nodeName === 'TEXTAREA')
+  );
+}
+
+module.exports = isTextInputElement;
+
+},{}],140:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule isTextNode
+ * @typechecks
+ */
+
+var isNode = require("./isNode");
+
+/**
+ * @param {*} object The object to check.
+ * @return {boolean} Whether or not the object is a DOM text node.
+ */
+function isTextNode(object) {
+  return isNode(object) && object.nodeType == 3;
+}
+
+module.exports = isTextNode;
+
+},{"./isNode":138}],141:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyMirror
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var invariant = require("./invariant");
+
+/**
+ * Constructs an enumeration with keys equal to their value.
+ *
+ * For example:
+ *
+ *   var COLORS = keyMirror({blue: null, red: null});
+ *   var myColor = COLORS.blue;
+ *   var isColorValid = !!COLORS[myColor];
+ *
+ * The last line could not be performed if the values of the generated enum were
+ * not equal to their keys.
+ *
+ *   Input:  {key1: val1, key2: val2}
+ *   Output: {key1: key1, key2: key2}
+ *
+ * @param {object} obj
+ * @return {object}
+ */
+var keyMirror = function(obj) {
+  var ret = {};
+  var key;
+  ("production" !== process.env.NODE_ENV ? invariant(
+    obj instanceof Object && !Array.isArray(obj),
+    'keyMirror(...): Argument must be an object.'
+  ) : invariant(obj instanceof Object && !Array.isArray(obj)));
+  for (key in obj) {
+    if (!obj.hasOwnProperty(key)) {
+      continue;
+    }
+    ret[key] = key;
+  }
+  return ret;
+};
+
+module.exports = keyMirror;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],142:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyOf
+ */
+
+/**
+ * Allows extraction of a minified key. Let's the build system minify keys
+ * without loosing the ability to dynamically use key strings as values
+ * themselves. Pass in an object with a single key/val pair and it will return
+ * you the string key of that single record. Suppose you want to grab the
+ * value for a key 'className' inside of an object. Key/val minification may
+ * have aliased that key to be 'xa12'. keyOf({className: null}) will return
+ * 'xa12' in that case. Resolve keys you want to use once at startup time, then
+ * reuse those resolutions.
+ */
+var keyOf = function(oneKeyObj) {
+  var key;
+  for (key in oneKeyObj) {
+    if (!oneKeyObj.hasOwnProperty(key)) {
+      continue;
+    }
+    return key;
+  }
+  return null;
+};
+
+
+module.exports = keyOf;
+
+},{}],143:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule mapObject
+ */
+
+'use strict';
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Executes the provided `callback` once for each enumerable own property in the
+ * object and constructs a new object from the results. The `callback` is
+ * invoked with three arguments:
+ *
+ *  - the property value
+ *  - the property name
+ *  - the object being traversed
+ *
+ * Properties that are added after the call to `mapObject` will not be visited
+ * by `callback`. If the values of existing properties are changed, the value
+ * passed to `callback` will be the value at the time `mapObject` visits them.
+ * Properties that are deleted before being visited are not visited.
+ *
+ * @grep function objectMap()
+ * @grep function objMap()
+ *
+ * @param {?object} object
+ * @param {function} callback
+ * @param {*} context
+ * @return {?object}
+ */
+function mapObject(object, callback, context) {
+  if (!object) {
+    return null;
+  }
+  var result = {};
+  for (var name in object) {
+    if (hasOwnProperty.call(object, name)) {
+      result[name] = callback.call(context, object[name], name, object);
+    }
+  }
+  return result;
+}
+
+module.exports = mapObject;
+
+},{}],144:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule memoizeStringOnly
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/**
+ * Memoizes the return value of a function that accepts one string argument.
+ *
+ * @param {function} callback
+ * @return {function}
+ */
+function memoizeStringOnly(callback) {
+  var cache = {};
+  return function(string) {
+    if (!cache.hasOwnProperty(string)) {
+      cache[string] = callback.call(this, string);
+    }
+    return cache[string];
+  };
+}
+
+module.exports = memoizeStringOnly;
+
+},{}],145:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule onlyChild
+ */
+'use strict';
+
+var ReactElement = require("./ReactElement");
+
+var invariant = require("./invariant");
+
+/**
+ * Returns the first child in a collection of children and verifies that there
+ * is only one child in the collection. The current implementation of this
+ * function assumes that a single child gets passed without a wrapper, but the
+ * purpose of this helper function is to abstract away the particular structure
+ * of children.
+ *
+ * @param {?object} children Child collection structure.
+ * @return {ReactComponent} The first and only `ReactComponent` contained in the
+ * structure.
+ */
+function onlyChild(children) {
+  ("production" !== process.env.NODE_ENV ? invariant(
+    ReactElement.isValidElement(children),
+    'onlyChild must be passed a children with exactly one child.'
+  ) : invariant(ReactElement.isValidElement(children)));
+  return children;
+}
+
+module.exports = onlyChild;
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./invariant":136,"_process":157}],146:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performance
+ * @typechecks
+ */
+
+"use strict";
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var performance;
+
+if (ExecutionEnvironment.canUseDOM) {
+  performance =
+    window.performance ||
+    window.msPerformance ||
+    window.webkitPerformance;
+}
+
+module.exports = performance || {};
+
+},{"./ExecutionEnvironment":21}],147:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule performanceNow
+ * @typechecks
+ */
+
+var performance = require("./performance");
+
+/**
+ * Detect if we can use `window.performance.now()` and gracefully fallback to
+ * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
+ * because of Facebook's testing infrastructure.
+ */
+if (!performance || !performance.now) {
+  performance = Date;
+}
+
+var performanceNow = performance.now.bind(performance);
+
+module.exports = performanceNow;
+
+},{"./performance":146}],148:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule quoteAttributeValueForBrowser
+ */
+
+'use strict';
+
+var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
+
+/**
+ * Escapes attribute value to prevent scripting attacks.
+ *
+ * @param {*} value Value to escape.
+ * @return {string} An escaped string.
+ */
+function quoteAttributeValueForBrowser(value) {
+  return '"' + escapeTextContentForBrowser(value) + '"';
+}
+
+module.exports = quoteAttributeValueForBrowser;
+
+},{"./escapeTextContentForBrowser":117}],149:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule setInnerHTML
+ */
+
+/* globals MSApp */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+
+var WHITESPACE_TEST = /^[ \r\n\t\f]/;
+var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;
+
+/**
+ * Set the innerHTML property of a node, ensuring that whitespace is preserved
+ * even in IE8.
+ *
+ * @param {DOMElement} node
+ * @param {string} html
+ * @internal
+ */
+var setInnerHTML = function(node, html) {
+  node.innerHTML = html;
+};
+
+// Win8 apps: Allow all html to be inserted
+if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) {
+  setInnerHTML = function(node, html) {
+    MSApp.execUnsafeLocalFunction(function() {
+      node.innerHTML = html;
+    });
+  };
+}
+
+if (ExecutionEnvironment.canUseDOM) {
+  // IE8: When updating a just created node with innerHTML only leading
+  // whitespace is removed. When updating an existing node with innerHTML
+  // whitespace in root TextNodes is also collapsed.
+  // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html
+
+  // Feature detection; only IE8 is known to behave improperly like this.
+  var testElement = document.createElement('div');
+  testElement.innerHTML = ' ';
+  if (testElement.innerHTML === '') {
+    setInnerHTML = function(node, html) {
+      // Magic theory: IE8 supposedly differentiates between added and updated
+      // nodes when processing innerHTML, innerHTML on updated nodes suffers
+      // from worse whitespace behavior. Re-adding a node like this triggers
+      // the initial and more favorable whitespace behavior.
+      // TODO: What to do on a detached node?
+      if (node.parentNode) {
+        node.parentNode.replaceChild(node, node);
+      }
+
+      // We also implement a workaround for non-visible tags disappearing into
+      // thin air on IE8, this only happens if there is no visible text
+      // in-front of the non-visible tags. Piggyback on the whitespace fix
+      // and simply check if any non-visible tags appear in the source.
+      if (WHITESPACE_TEST.test(html) ||
+          html[0] === '<' && NONVISIBLE_TEST.test(html)) {
+        // Recover leading whitespace by temporarily prepending any character.
+        // \uFEFF has the potential advantage of being zero-width/invisible.
+        node.innerHTML = '\uFEFF' + html;
+
+        // deleteData leaves an empty `TextNode` which offsets the index of all
+        // children. Definitely want to avoid this.
+        var textNode = node.firstChild;
+        if (textNode.data.length === 1) {
+          node.removeChild(textNode);
+        } else {
+          textNode.deleteData(0, 1);
+        }
+      } else {
+        node.innerHTML = html;
+      }
+    };
+  }
+}
+
+module.exports = setInnerHTML;
+
+},{"./ExecutionEnvironment":21}],150:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule setTextContent
+ */
+
+'use strict';
+
+var ExecutionEnvironment = require("./ExecutionEnvironment");
+var escapeTextContentForBrowser = require("./escapeTextContentForBrowser");
+var setInnerHTML = require("./setInnerHTML");
+
+/**
+ * Set the textContent property of a node, ensuring that whitespace is preserved
+ * even in IE8. innerText is a poor substitute for textContent and, among many
+ * issues, inserts <br> instead of the literal newline chars. innerHTML behaves
+ * as it should.
+ *
+ * @param {DOMElement} node
+ * @param {string} text
+ * @internal
+ */
+var setTextContent = function(node, text) {
+  node.textContent = text;
+};
+
+if (ExecutionEnvironment.canUseDOM) {
+  if (!('textContent' in document.documentElement)) {
+    setTextContent = function(node, text) {
+      setInnerHTML(node, escapeTextContentForBrowser(text));
+    };
+  }
+}
+
+module.exports = setTextContent;
+
+},{"./ExecutionEnvironment":21,"./escapeTextContentForBrowser":117,"./setInnerHTML":149}],151:[function(require,module,exports){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shallowEqual
+ */
+
+'use strict';
+
+/**
+ * Performs equality by iterating through keys on an object and returning
+ * false when any key has values which are not strictly equal between
+ * objA and objB. Returns true when the values of all keys are strictly equal.
+ *
+ * @return {boolean}
+ */
+function shallowEqual(objA, objB) {
+  if (objA === objB) {
+    return true;
+  }
+  var key;
+  // Test for A's keys different from B.
+  for (key in objA) {
+    if (objA.hasOwnProperty(key) &&
+        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
+      return false;
+    }
+  }
+  // Test for B's keys missing from A.
+  for (key in objB) {
+    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+module.exports = shallowEqual;
+
+},{}],152:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shouldUpdateReactComponent
+ * @typechecks static-only
+ */
+
+'use strict';
+
+var warning = require("./warning");
+
+/**
+ * Given a `prevElement` and `nextElement`, determines if the existing
+ * instance should be updated as opposed to being destroyed or replaced by a new
+ * instance. Both arguments are elements. This ensures that this logic can
+ * operate on stateless trees without any backing instance.
+ *
+ * @param {?object} prevElement
+ * @param {?object} nextElement
+ * @return {boolean} True if the existing instance should be updated.
+ * @protected
+ */
+function shouldUpdateReactComponent(prevElement, nextElement) {
+  if (prevElement != null && nextElement != null) {
+    var prevType = typeof prevElement;
+    var nextType = typeof nextElement;
+    if (prevType === 'string' || prevType === 'number') {
+      return (nextType === 'string' || nextType === 'number');
+    } else {
+      if (nextType === 'object' &&
+          prevElement.type === nextElement.type &&
+          prevElement.key === nextElement.key) {
+        var ownersMatch = prevElement._owner === nextElement._owner;
+        var prevName = null;
+        var nextName = null;
+        var nextDisplayName = null;
+        if ("production" !== process.env.NODE_ENV) {
+          if (!ownersMatch) {
+            if (prevElement._owner != null &&
+                prevElement._owner.getPublicInstance() != null &&
+                prevElement._owner.getPublicInstance().constructor != null) {
+              prevName =
+                prevElement._owner.getPublicInstance().constructor.displayName;
+            }
+            if (nextElement._owner != null &&
+                nextElement._owner.getPublicInstance() != null &&
+                nextElement._owner.getPublicInstance().constructor != null) {
+              nextName =
+                nextElement._owner.getPublicInstance().constructor.displayName;
+            }
+            if (nextElement.type != null &&
+                nextElement.type.displayName != null) {
+              nextDisplayName = nextElement.type.displayName;
+            }
+            if (nextElement.type != null && typeof nextElement.type === 'string') {
+              nextDisplayName = nextElement.type;
+            }
+            if (typeof nextElement.type !== 'string' ||
+                nextElement.type === 'input' ||
+                nextElement.type === 'textarea') {
+              if ((prevElement._owner != null &&
+                  prevElement._owner._isOwnerNecessary === false) ||
+                  (nextElement._owner != null &&
+                  nextElement._owner._isOwnerNecessary === false)) {
+                if (prevElement._owner != null) {
+                  prevElement._owner._isOwnerNecessary = true;
+                }
+                if (nextElement._owner != null) {
+                  nextElement._owner._isOwnerNecessary = true;
+                }
+                ("production" !== process.env.NODE_ENV ? warning(
+                  false,
+                  '<%s /> is being rendered by both %s and %s using the same ' +
+                  'key (%s) in the same place. Currently, this means that ' +
+                  'they don\'t preserve state. This behavior should be very ' +
+                  'rare so we\'re considering deprecating it. Please contact ' +
+                  'the React team and explain your use case so that we can ' +
+                  'take that into consideration.',
+                  nextDisplayName || 'Unknown Component',
+                  prevName || '[Unknown]',
+                  nextName || '[Unknown]',
+                  prevElement.key
+                ) : null);
+              }
+            }
+          }
+        }
+        return ownersMatch;
+      }
+    }
+  }
+  return false;
+}
+
+module.exports = shouldUpdateReactComponent;
+
+}).call(this,require('_process'))
+},{"./warning":155,"_process":157}],153:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule toArray
+ * @typechecks
+ */
+
+var invariant = require("./invariant");
+
+/**
+ * Convert array-like objects to arrays.
+ *
+ * This API assumes the caller knows the contents of the data type. For less
+ * well defined inputs use createArrayFromMixed.
+ *
+ * @param {object|function|filelist} obj
+ * @return {array}
+ */
+function toArray(obj) {
+  var length = obj.length;
+
+  // Some browse builtin objects can report typeof 'function' (e.g. NodeList in
+  // old versions of Safari).
+  ("production" !== process.env.NODE_ENV ? invariant(
+    !Array.isArray(obj) &&
+    (typeof obj === 'object' || typeof obj === 'function'),
+    'toArray: Array-like object expected'
+  ) : invariant(!Array.isArray(obj) &&
+  (typeof obj === 'object' || typeof obj === 'function')));
+
+  ("production" !== process.env.NODE_ENV ? invariant(
+    typeof length === 'number',
+    'toArray: Object needs a length property'
+  ) : invariant(typeof length === 'number'));
+
+  ("production" !== process.env.NODE_ENV ? invariant(
+    length === 0 ||
+    (length - 1) in obj,
+    'toArray: Object should have keys for indices'
+  ) : invariant(length === 0 ||
+  (length - 1) in obj));
+
+  // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
+  // without method will throw during the slice call and skip straight to the
+  // fallback.
+  if (obj.hasOwnProperty) {
+    try {
+      return Array.prototype.slice.call(obj);
+    } catch (e) {
+      // IE < 9 does not support Array#slice on collections objects
+    }
+  }
+
+  // Fall back to copying key by key. This assumes all keys have a value,
+  // so will not preserve sparsely populated inputs.
+  var ret = Array(length);
+  for (var ii = 0; ii < length; ii++) {
+    ret[ii] = obj[ii];
+  }
+  return ret;
+}
+
+module.exports = toArray;
+
+}).call(this,require('_process'))
+},{"./invariant":136,"_process":157}],154:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule traverseAllChildren
+ */
+
+'use strict';
+
+var ReactElement = require("./ReactElement");
+var ReactFragment = require("./ReactFragment");
+var ReactInstanceHandles = require("./ReactInstanceHandles");
+
+var getIteratorFn = require("./getIteratorFn");
+var invariant = require("./invariant");
+var warning = require("./warning");
+
+var SEPARATOR = ReactInstanceHandles.SEPARATOR;
+var SUBSEPARATOR = ':';
+
+/**
+ * TODO: Test that a single child and an array with one item have the same key
+ * pattern.
+ */
+
+var userProvidedKeyEscaperLookup = {
+  '=': '=0',
+  '.': '=1',
+  ':': '=2'
+};
+
+var userProvidedKeyEscapeRegex = /[=.:]/g;
+
+var didWarnAboutMaps = false;
+
+function userProvidedKeyEscaper(match) {
+  return userProvidedKeyEscaperLookup[match];
+}
+
+/**
+ * Generate a key string that identifies a component within a set.
+ *
+ * @param {*} component A component that could contain a manual key.
+ * @param {number} index Index that is used if a manual key is not provided.
+ * @return {string}
+ */
+function getComponentKey(component, index) {
+  if (component && component.key != null) {
+    // Explicit key
+    return wrapUserProvidedKey(component.key);
+  }
+  // Implicit key determined by the index in the set
+  return index.toString(36);
+}
+
+/**
+ * Escape a component key so that it is safe to use in a reactid.
+ *
+ * @param {*} key Component key to be escaped.
+ * @return {string} An escaped string.
+ */
+function escapeUserProvidedKey(text) {
+  return ('' + text).replace(
+    userProvidedKeyEscapeRegex,
+    userProvidedKeyEscaper
+  );
+}
+
+/**
+ * Wrap a `key` value explicitly provided by the user to distinguish it from
+ * implicitly-generated keys generated by a component's index in its parent.
+ *
+ * @param {string} key Value of a user-provided `key` attribute
+ * @return {string}
+ */
+function wrapUserProvidedKey(key) {
+  return '$' + escapeUserProvidedKey(key);
+}
+
+/**
+ * @param {?*} children Children tree container.
+ * @param {!string} nameSoFar Name of the key path so far.
+ * @param {!number} indexSoFar Number of children encountered until this point.
+ * @param {!function} callback Callback to invoke with each child found.
+ * @param {?*} traverseContext Used to pass information throughout the traversal
+ * process.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildrenImpl(
+  children,
+  nameSoFar,
+  indexSoFar,
+  callback,
+  traverseContext
+) {
+  var type = typeof children;
+
+  if (type === 'undefined' || type === 'boolean') {
+    // All of the above are perceived as null.
+    children = null;
+  }
+
+  if (children === null ||
+      type === 'string' ||
+      type === 'number' ||
+      ReactElement.isValidElement(children)) {
+    callback(
+      traverseContext,
+      children,
+      // If it's the only child, treat the name as if it was wrapped in an array
+      // so that it's consistent if the number of children grows.
+      nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar,
+      indexSoFar
+    );
+    return 1;
+  }
+
+  var child, nextName, nextIndex;
+  var subtreeCount = 0; // Count of children found in the current subtree.
+
+  if (Array.isArray(children)) {
+    for (var i = 0; i < children.length; i++) {
+      child = children[i];
+      nextName = (
+        (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+        getComponentKey(child, i)
+      );
+      nextIndex = indexSoFar + subtreeCount;
+      subtreeCount += traverseAllChildrenImpl(
+        child,
+        nextName,
+        nextIndex,
+        callback,
+        traverseContext
+      );
+    }
+  } else {
+    var iteratorFn = getIteratorFn(children);
+    if (iteratorFn) {
+      var iterator = iteratorFn.call(children);
+      var step;
+      if (iteratorFn !== children.entries) {
+        var ii = 0;
+        while (!(step = iterator.next()).done) {
+          child = step.value;
+          nextName = (
+            (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+            getComponentKey(child, ii++)
+          );
+          nextIndex = indexSoFar + subtreeCount;
+          subtreeCount += traverseAllChildrenImpl(
+            child,
+            nextName,
+            nextIndex,
+            callback,
+            traverseContext
+          );
+        }
+      } else {
+        if ("production" !== process.env.NODE_ENV) {
+          ("production" !== process.env.NODE_ENV ? warning(
+            didWarnAboutMaps,
+            'Using Maps as children is not yet fully supported. It is an ' +
+            'experimental feature that might be removed. Convert it to a ' +
+            'sequence / iterable of keyed ReactElements instead.'
+          ) : null);
+          didWarnAboutMaps = true;
+        }
+        // Iterator will provide entry [k,v] tuples rather than values.
+        while (!(step = iterator.next()).done) {
+          var entry = step.value;
+          if (entry) {
+            child = entry[1];
+            nextName = (
+              (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+              wrapUserProvidedKey(entry[0]) + SUBSEPARATOR +
+              getComponentKey(child, 0)
+            );
+            nextIndex = indexSoFar + subtreeCount;
+            subtreeCount += traverseAllChildrenImpl(
+              child,
+              nextName,
+              nextIndex,
+              callback,
+              traverseContext
+            );
+          }
+        }
+      }
+    } else if (type === 'object') {
+      ("production" !== process.env.NODE_ENV ? invariant(
+        children.nodeType !== 1,
+        'traverseAllChildren(...): Encountered an invalid child; DOM ' +
+        'elements are not valid children of React components.'
+      ) : invariant(children.nodeType !== 1));
+      var fragment = ReactFragment.extract(children);
+      for (var key in fragment) {
+        if (fragment.hasOwnProperty(key)) {
+          child = fragment[key];
+          nextName = (
+            (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) +
+            wrapUserProvidedKey(key) + SUBSEPARATOR +
+            getComponentKey(child, 0)
+          );
+          nextIndex = indexSoFar + subtreeCount;
+          subtreeCount += traverseAllChildrenImpl(
+            child,
+            nextName,
+            nextIndex,
+            callback,
+            traverseContext
+          );
+        }
+      }
+    }
+  }
+
+  return subtreeCount;
+}
+
+/**
+ * Traverses children that are typically specified as `props.children`, but
+ * might also be specified through attributes:
+ *
+ * - `traverseAllChildren(this.props.children, ...)`
+ * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
+ *
+ * The `traverseContext` is an optional argument that is passed through the
+ * entire traversal. It can be used to store accumulations or anything else that
+ * the callback might find relevant.
+ *
+ * @param {?*} children Children tree object.
+ * @param {!function} callback To invoke upon traversing each child.
+ * @param {?*} traverseContext Context for traversal.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildren(children, callback, traverseContext) {
+  if (children == null) {
+    return 0;
+  }
+
+  return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
+}
+
+module.exports = traverseAllChildren;
+
+}).call(this,require('_process'))
+},{"./ReactElement":58,"./ReactFragment":64,"./ReactInstanceHandles":67,"./getIteratorFn":127,"./invariant":136,"./warning":155,"_process":157}],155:[function(require,module,exports){
+(function (process){
+/**
+ * Copyright 2014-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule warning
+ */
+
+"use strict";
+
+var emptyFunction = require("./emptyFunction");
+
+/**
+ * Similar to invariant but only logs a warning if the condition is not met.
+ * This can be used to log issues in development environments in critical
+ * paths. Removing the logging code for production environments will keep the
+ * same logic and follow the same code paths.
+ */
+
+var warning = emptyFunction;
+
+if ("production" !== process.env.NODE_ENV) {
+  warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
+    if (format === undefined) {
+      throw new Error(
+        '`warning(condition, format, ...args)` requires a warning ' +
+        'message argument'
+      );
+    }
+
+    if (format.length < 10 || /^[s\W]*$/.test(format)) {
+      throw new Error(
+        'The warning format should be able to uniquely identify this ' +
+        'warning. Please, use a more descriptive format than: ' + format
+      );
+    }
+
+    if (format.indexOf('Failed Composite propType: ') === 0) {
+      return; // Ignore CompositeComponent proptype check.
+    }
+
+    if (!condition) {
+      var argIndex = 0;
+      var message = 'Warning: ' + format.replace(/%s/g, function()  {return args[argIndex++];});
+      console.warn(message);
+      try {
+        // --- Welcome to debugging React ---
+        // This error was thrown as a convenience so that you can use this stack
+        // to find the callsite that caused this warning to fire.
+        throw new Error(message);
+      } catch(x) {}
+    }
+  };
+}
+
+module.exports = warning;
+
+}).call(this,require('_process'))
+},{"./emptyFunction":115,"_process":157}],156:[function(require,module,exports){
+module.exports = require('./lib/React');
+
+},{"./lib/React":29}],157:[function(require,module,exports){
+// shim for using process in browser
+
+var process = module.exports = {};
+var queue = [];
+var draining = false;
+
+function drainQueue() {
+    if (draining) {
+        return;
+    }
+    draining = true;
+    var currentQueue;
+    var len = queue.length;
+    while(len) {
+        currentQueue = queue;
+        queue = [];
+        var i = -1;
+        while (++i < len) {
+            currentQueue[i]();
+        }
+        len = queue.length;
+    }
+    draining = false;
+}
+process.nextTick = function (fun) {
+    queue.push(fun);
+    if (!draining) {
+        setTimeout(drainQueue, 0);
+    }
+};
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+
+process.binding = function (name) {
+    throw new Error('process.binding is not supported');
+};
+
+// TODO(shtylman)
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+    throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}]},{},[1])(1)
+});
diff --git a/webcore/test/TC/reactable.js b/webcore/test/TC/reactable.js
new file mode 100644
index 0000000..89cbd2c
--- /dev/null
+++ b/webcore/test/TC/reactable.js
@@ -0,0 +1,955 @@
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
+        define('reactable', ['react'], factory);
+    } else if (typeof exports === 'object') {
+        // Node. Does not work with strict CommonJS, but
+        // only CommonJS-like environments that support module.exports,
+        // like Node.
+        module.exports = factory(require('react'));
+    } else {
+        // Browser globals (root is window)
+        root.Reactable = factory(root.React);
+    }
+}(this, function (React) {
+    "use strict";
+    var exports = {};
+
+    // Array.prototype.map polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill
+    // Production steps of ECMA-262, Edition 5, 15.4.4.19
+    // Reference: http://es5.github.io/#x15.4.4.19
+    if (!Array.prototype.map) {
+
+        Array.prototype.map = function(callback, thisArg) {
+            var T, A, k;
+
+            if (this === null) {
+                throw new TypeError(" this is null or not defined");
+            }
+
+            var O = Object(this);
+            var len = O.length >>> 0;
+
+            if (typeof callback !== "function") {
+                throw new TypeError(callback + " is not a function");
+            }
+
+            if (arguments.length > 1) {
+                T = thisArg;
+            }
+
+            A = new Array(len);
+            k = 0;
+
+            while (k < len) {
+                var kValue, mappedValue;
+                if (k in O) {
+                    kValue = O[k];
+                    mappedValue = callback.call(T, kValue, k, O);
+                    A[k] = mappedValue;
+                }
+                k++;
+            }
+            return A;
+        };
+    }
+
+    // Array.prototype.indexOf polyfill for IE8
+    if (!Array.prototype.indexOf) {
+        Array.prototype.indexOf = function(elt /*, from*/) {
+            var len = this.length >>> 0;
+
+            var from = Number(arguments[1]) || 0;
+            from = (from < 0) ? Math.ceil(from) : Math.floor(from);
+            if (from < 0) {
+                from += len;
+            }
+
+            for (; from < len; from++) {
+                if (from in this && this[from] === elt) {
+                    return from;
+                }
+            }
+            return -1;
+        };
+    }
+
+    // Array.prototype.find polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
+    if (!Array.prototype.find) {
+        Object.defineProperty(Array.prototype, 'find', {
+            enumerable: false,
+            configurable: true,
+            writable: true,
+            value: function(predicate) {
+                if (this === null) {
+                    throw new TypeError('Array.prototype.find called on null or undefined');
+                }
+                if (typeof predicate !== 'function') {
+                    throw new TypeError('predicate must be a function');
+                }
+                var list = Object(this);
+                var length = list.length >>> 0;
+                var thisArg = arguments[1];
+                var value;
+
+                for (var i = 0; i < length; i++) {
+                    if (i in list) {
+                        value = list[i];
+                        if (predicate.call(thisArg, value, i, list)) {
+                            return value;
+                        }
+                    }
+                }
+                return undefined;
+            }
+        });
+    }
+
+    if (!Array.isArray) {
+        Array.isArray = function (value) {
+            return Object.prototype.toString.call(value) === '[object Array]';
+        };
+    }
+
+    if (!Object.assign) {
+        Object.defineProperty(Object, "assign", {
+            enumerable: false,
+            configurable: true,
+            writable: true,
+            value: function(target, firstSource) {
+                if (target === undefined || target === null)
+                    throw new TypeError("Cannot convert first argument to object");
+                var to = Object(target);
+                for (var i = 1; i < arguments.length; i++) {
+                    var nextSource = arguments[i];
+                    if (nextSource === undefined || nextSource === null) continue;
+                    var keysArray = Object.keys(Object(nextSource));
+                    for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
+                        var nextKey = keysArray[nextIndex];
+                        var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
+                        if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey];
+                    }
+                }
+                return to;
+            }
+        });
+    }
+
+    function Unsafe(content) {
+        this.content = content;
+    }
+
+    Unsafe.prototype.toString = function() {
+        return this.content;
+    };
+
+    function stringable(thing) {
+        return thing !== null && typeof(thing) !== 'undefined' && typeof(thing.toString === 'function');
+    }
+
+    // this is a bit hacky - it'd be nice if React exposed an API for this
+    function isReactComponent(thing) {
+        return thing !== null && typeof(thing) === 'object' && typeof(thing.props) !== 'undefined';
+    }
+
+    React.Children.children = function(children) {
+        return React.Children.map(children, function(x) { return x; }) || [];
+    };
+
+    exports.unsafe = function(str) {
+        return new Unsafe(str);
+    };
+
+    exports.Sort = {
+        Numeric: function(a, b) {
+            var valA = parseFloat(a.toString().replace(',', ''));
+            var valB = parseFloat(b.toString().replace(',', ''));
+
+            // Sort non-numeric values alphabetically at the bottom of the list
+            if (isNaN(valA) && isNaN(valB)) {
+                valA = a;
+                valB = b;
+            } else {
+                if (isNaN(valA)) {
+                    return 1;
+                }
+                if (isNaN(valB)) {
+                    return -1;
+                }
+            }
+
+            if (valA < valB) {
+                return -1;
+            }
+            if (valA > valB) {
+                return 1;
+            }
+
+            return 0;
+        },
+
+        NumericInteger: function(a, b) {
+          if (isNaN(a) || isNaN(b)) {
+            return a > b ? 1 : -1;
+          }
+
+          return a - b;
+        },
+
+        Currency: function(a, b) {
+            // Parse out dollar signs, then do a regular numeric sort
+            // TODO: handle non-American currency
+
+            if (a[0] === '$') {
+                a = a.substring(1);
+            }
+            if (b[0] === '$') {
+                b = b.substring(1);
+            }
+
+            return exports.Sort.Numeric(a, b);
+        },
+
+        Date: function(a, b) {
+            // Note: this function tries to do a standard javascript string -> date conversion
+            // If you need more control over the date string format, consider using a different
+            // date library and writing your own function
+            var valA = Date.parse(a);
+            var valB = Date.parse(b);
+
+            // Handle non-date values with numeric sort
+            // Sort non-numeric values alphabetically at the bottom of the list
+            if (isNaN(valA) || isNaN(valB)) {
+                return exports.Sort.Numeric(a, b);
+            }
+
+            if (valA > valB) {
+                return 1;
+            }
+            if (valB > valA) {
+                return -1;
+            }
+
+            return 0;
+        },
+
+        CaseInsensitive: function(a, b) {
+            return a.toLowerCase().localeCompare(b.toLowerCase());
+        }
+    };
+
+    var Td = exports.Td = React.createClass({displayName: "Td",
+        handleClick: function(e){
+            if (typeof this.props.handleClick === 'function') {
+                return this.props.handleClick(e, this);
+            }
+        },
+        render: function() {
+            var tdProps = {
+                className: this.props.className,
+                onClick: this.handleClick
+            };
+
+            // Attach any properties on the column to this Td object to allow things like custom event handlers
+            if (typeof(this.props.column) === 'object') {
+                for (var key in this.props.column) {
+                    if (key !== 'key' && key !== 'name') {
+                        tdProps[key] = this.props.column[key];
+                    }
+                }
+            }
+
+            var data = this.props.data;
+
+            if (typeof(this.props.children) !== 'undefined') {
+                if (isReactComponent(this.props.children)) {
+                    data = this.props.children;
+                } else if (
+                    typeof(this.props.data) === 'undefined' &&
+                        stringable(this.props.children)
+                ) {
+                    data = this.props.children.toString();
+                }
+
+                if (this.props.children instanceof Unsafe) {
+                    tdProps.dangerouslySetInnerHTML = { __html: this.props.children.toString() };
+                } else {
+                    tdProps.children = data;
+                }
+            }
+
+            return React.DOM.td(tdProps);
+        }
+    });
+
+
+    var Tr = exports.Tr = React.createClass({displayName: "Tr",
+        statics: {
+            childNode: Td,
+            dataType: 'object'
+        },
+        render: function() {
+            var children = toArray(React.Children.children(this.props.children));
+
+            if (
+                this.props.data &&
+                    this.props.columns &&
+                        typeof this.props.columns.map === 'function'
+            ) {
+                if (typeof(children.concat) === 'undefined') { console.log(children); }
+
+                children = children.concat(this.props.columns.map(function(column, i) {
+                    if (this.props.data.hasOwnProperty(column.key)) {
+                        var value = this.props.data[column.key];
+                        var props = {};
+
+                        if (
+                            typeof(value) !== 'undefined' &&
+                                value !== null &&
+                                    value.__reactableMeta === true
+                        ) {
+                            props = value.props;
+                            value = value.value;
+                        }
+
+                        return React.createElement(Td, React.__spread({column: column, key: column.key},  props), value);
+                    } else {
+                        return React.createElement(Td, {column: column, key: column.key});
+                    }
+                }.bind(this)));
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return React.DOM.tr(props, children);
+        }
+    });
+
+    var Thead = exports.Thead = React.createClass({displayName: "Thead",
+        getColumns: function() {
+            return React.Children.map(this.props.children, function(th) {
+                if (typeof th.props.children === 'string') {
+                    return th.props.children;
+                } else {
+                    throw new TypeError('<th> must have a string child');
+                }
+            });
+        },
+        handleClickTh: function (column) {
+            this.props.onSort(column.key);
+        },
+        render: function() {
+
+            // Declare the list of Ths
+            var Ths = [];
+            for (var index = 0; index < this.props.columns.length; index++) {
+                var column = this.props.columns[index];
+                var sortClass = '';
+
+                if (this.props.sortableColumns[column.key]) {
+                    sortClass += 'reactable-header-sortable ';
+                }
+
+                if (this.props.sort.column === column.key) {
+                    sortClass += 'reactable-header-sort';
+                    if (this.props.sort.direction === 1) {
+                        sortClass += '-asc';
+                    }
+                    else {
+                        sortClass += '-desc';
+                    }
+                }
+
+                Ths.push(
+                    React.createElement(Th, {className: sortClass, key: index, onClick: this.handleClickTh.bind(this, column)}, 
+                        column.label
+                    )
+                );
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return (
+                React.createElement("thead", React.__spread({},  props), 
+                    this.props.filtering === true ?
+                        React.createElement(Filterer, {
+                            colSpan: this.props.columns.length, 
+                            onFilter: this.props.onFilter, 
+                            placeholder: this.props.filterPlaceholder, 
+                            value: this.props.currentFilter}
+                        ) : '', 
+                    React.createElement("tr", {className: "reactable-column-header"}, Ths)
+                )
+            );
+        }
+    });
+
+    var Th = exports.Th = React.createClass({displayName: "Th",
+        render: function() {
+                var childProps
+            if (this.props.children instanceof Unsafe) {
+                return React.createElement("th", React.__spread({},  filterPropsFrom(this.props), 
+                    {dangerouslySetInnerHTML: {__html: this.props.children.toString()}}))
+            } else {
+                return React.createElement("th", React.__spread({},  filterPropsFrom(this.props)), 
+                    this.props.children
+                );
+            }
+        }
+    });
+
+    var FiltererInput = React.createClass({displayName: "FiltererInput",
+        onChange: function() {
+            this.props.onFilter(this.getDOMNode().value);
+        },
+        render: function() {
+            return (
+                React.createElement("input", {type: "text", 
+                    className: "reactable-filter-input", 
+                    placeholder: this.props.placeholder, 
+                    value: this.props.value, 
+                    onKeyUp: this.onChange, 
+                    onChange: this.onChange})
+            );
+        }
+    });
+
+    var Filterer = React.createClass({displayName: "Filterer",
+        render: function() {
+            if (typeof this.props.colSpan === 'undefined') {
+                throw new TypeError('Must pass a colSpan argument to Filterer');
+            }
+
+            return (
+                React.createElement("tr", {className: "reactable-filterer"}, 
+                    React.createElement("td", {colSpan: this.props.colSpan}, 
+                        React.createElement(FiltererInput, {onFilter: this.props.onFilter, 
+                            value: this.props.value, 
+                            placeholder: this.props.placeholder})
+                    )
+                )
+            );
+        }
+    });
+
+    var Paginator = React.createClass({displayName: "Paginator",
+        render: function() {
+            if (typeof this.props.colSpan === 'undefined') {
+                throw new TypeError('Must pass a colSpan argument to Paginator');
+            }
+
+            if (typeof this.props.numPages === 'undefined') {
+                throw new TypeError('Must pass a non-zero numPages argument to Paginator');
+            }
+
+            if (typeof this.props.currentPage === 'undefined') {
+                throw new TypeError('Must pass a currentPage argument to Paginator');
+            }
+
+            var pageButtons = [];
+            for (var i = 0; i < this.props.numPages; i++) {
+                var pageNum = i;
+                var className = "reactable-page-button";
+                if (this.props.currentPage === i) {
+                    className += " reactable-current-page";
+                }
+
+                pageButtons.push(
+                    React.createElement("a", {className: className, key: i, 
+                        // create function to get around for-loop closure issue
+                        onClick: (function(pageNum) {
+                            return function() {
+                                this.props.onPageChange(pageNum);
+                            }.bind(this);
+                        }.bind(this))(i)}, i + 1)
+                );
+            }
+
+            return (
+                React.createElement("tbody", {className: "reactable-pagination"}, 
+                    React.createElement("tr", null, 
+                        React.createElement("td", {colSpan: this.props.colSpan}, 
+                            pageButtons
+                        )
+                    )
+                )
+            );
+        }
+    });
+
+    var Table = exports.Table = React.createClass({displayName: "Table",
+        // Translate a user defined column array to hold column objects if strings are specified
+        // (e.g. ['column1'] => [{key: 'column1', label: 'column1'}])
+        translateColumnsArray: function(columns) {
+            return columns.map(function(column, i) {
+                if (typeof(column) === 'string') {
+                    return {
+                        key:   column,
+                        label: column
+                    };
+                } else {
+                    if (typeof(column.sortable) !== 'undefined') {
+                        var sortFunction = column.sortable === true ? 'default' : column.sortable;
+                        this._sortable[column.key] = sortFunction;
+                    }
+
+                    return column;
+                }
+            }.bind(this));
+        },
+        parseChildData: function(props) {
+            var data = [];
+
+            // Transform any children back to a data array
+            if (typeof(props.children) !== 'undefined') {
+                React.Children.forEach(props.children, function(child) {
+                    // TODO: figure out a new way to determine the type of a component
+                    /*
+                       if (child.type.ConvenienceConstructor !== Tr) {
+                       return; // (continue)
+                       }
+                       */
+                    if (typeof(child.props) !== 'object') {
+                        return console.warn('Child passed to <Reactable.Table> was not an object: ' + child.toString());
+                    }
+
+                    var childData = child.props.data || {};
+
+                    React.Children.forEach(child.props.children, function(descendant) {
+                        // TODO
+                        /* if (descendant.type.ConvenienceConstructor === Td) { */
+                        if (true) {
+                            if (typeof(descendant.props.column) !== 'undefined') {
+                                var value;
+
+                                if (typeof(descendant.props.data) !== 'undefined') {
+                                    value = descendant.props.data;
+                                } else if (typeof(descendant.props.children) !== 'undefined') {
+                                    value = descendant.props.children;
+                                } else {
+                                    console.warn('exports.Td specified without ' +
+                                                 'a `data` property or children, ' +
+                                                 'ignoring');
+                                    return;
+                                }
+
+                                childData[descendant.props.column] = {
+                                    value: value,
+                                    props: filterPropsFrom(descendant.props),
+                                    __reactableMeta: true
+                                };
+                            } else {
+                                console.warn('exports.Td specified without a ' +
+                                             '`column` property, ignoring');
+                            }
+                        }
+                    });
+
+                    data.push({
+                        data: childData,
+                        props: filterPropsFrom(child.props),
+                        __reactableMeta: true
+                    });
+                }.bind(this));
+            }
+
+            return data;
+        },
+
+        initialize: function(props) {
+            this.data = props.data || [];
+            this.data = this.data.concat(this.parseChildData(props));
+            this.initializeSorts(props);
+        },
+
+        initializeSorts: function() {
+            this._sortable = {};
+            // Transform sortable properties into a more friendly list
+            for (var i in this.props.sortable) {
+                var column = this.props.sortable[i];
+                var columnName, sortFunction;
+
+                if (column instanceof Object) {
+                    if (typeof(column.column) !== 'undefined') {
+                        columnName = column.column;
+                    } else {
+                        console.warn('Sortable column specified without column name');
+                        return;
+                    }
+
+                    if (typeof(column.sortFunction) === 'function') {
+                        sortFunction = column.sortFunction;
+                    } else {
+                        sortFunction = 'default';
+                    }
+                } else {
+                    columnName      = column;
+                    sortFunction    = 'default';
+                }
+
+                this._sortable[columnName] = sortFunction;
+            }
+        },
+
+        getDefaultProps: function() {
+            var defaultProps = {
+                sortBy: false,
+                defaultSort: false,
+                itemsPerPage: 0,
+            };
+            return defaultProps;
+        },
+
+        getInitialState: function() {
+            var initialState = {
+                currentPage: 0,
+                currentSort: {
+                    column: null,
+                    direction: 1
+                },
+                filter: ''
+            };
+
+            // Set the state of the current sort to the default sort
+            if (this.props.sortBy !== false || this.props.defaultSort !== false) {
+                var sortingColumn = this.props.sortBy || this.props.defaultSort;
+                initialState.currentSort = this.getCurrentSort(sortingColumn);
+            }
+            return initialState;
+        },
+
+        getCurrentSort: function(column) {
+            var columnName, sortDirection;
+
+            if (column instanceof Object) {
+                if (typeof(column.column) !== 'undefined') {
+                    columnName = column.column;
+                } else {
+                    console.warn('Default column specified without column name');
+                    return;
+                }
+
+                if (typeof(column.direction) !== 'undefined') {
+                    if (column.direction === 1 || column.direction === 'asc') {
+                        sortDirection = 1;
+                    } else if (column.direction === -1 || column.direction === 'desc') {
+                        sortDirection = -1;
+                    } else {
+                        console.warn('Invalid default sort specified.  Defaulting to ascending');
+                        sortDirection = 1;
+                    }
+                } else {
+                    sortDirection = 1;
+                }
+            } else {
+                columnName      = column;
+                sortDirection   = 1;
+            }
+
+            return {
+                column: columnName,
+                direction: sortDirection
+            };
+        },
+
+        updateCurrentSort: function(sortBy) {
+            if (sortBy !== false &&
+                sortBy.column !== this.state.currentSort.column &&
+                    sortBy.direction !== this.state.currentSort.direction) {
+
+                this.setState({ currentSort: this.getCurrentSort(sortBy) });
+            }
+        },
+
+        componentWillMount: function() {
+            this.initialize(this.props);
+            this.sortByCurrentSort();
+        },
+        componentWillReceiveProps: function(nextProps) {
+            this.initialize(nextProps);
+            this.updateCurrentSort(nextProps.sortBy);
+            this.sortByCurrentSort();
+        },
+        onPageChange: function(page) {
+            this.setState({ currentPage: page });
+        },
+        filterBy: function(filter) {
+            this.setState({ filter: filter });
+        },
+        applyFilter: function(filter, children) {
+            // Helper function to apply filter text to a list of table rows
+            filter = filter.toLowerCase();
+            var matchedChildren = [];
+
+            for (var i = 0; i < children.length; i++) {
+                var data = children[i].props.data;
+
+                for (var j = 0; j < this.props.filterable.length; j++) {
+                    var filterColumn = this.props.filterable[j];
+
+                    if (
+                        typeof(data[filterColumn]) !== 'undefined' &&
+                            extractDataFrom(data, filterColumn).toString().toLowerCase().indexOf(filter) > -1
+                    ) {
+                        matchedChildren.push(children[i]);
+                        break;
+                    }
+                }
+            }
+
+            return matchedChildren;
+        },
+        sortByCurrentSort: function(){
+            // Apply a sort function according to the current sort in the state.
+            // This allows us to perform a default sort even on a non sortable column.
+            var currentSort = this.state.currentSort;
+
+            if (currentSort.column === null) {
+                return;
+            }
+
+            this.data.sort(function(a, b){
+                var keyA = extractDataFrom(a, currentSort.column);
+                keyA = (keyA instanceof Unsafe) ? keyA.toString() : keyA || '';
+                var keyB = extractDataFrom(b, currentSort.column);
+                keyB = (keyB instanceof Unsafe) ? keyB.toString() : keyB || '';
+
+                // Default sort
+                if (
+                    typeof(this._sortable[currentSort.column]) === 'undefined' ||
+                        this._sortable[currentSort.column] === 'default'
+                ) {
+
+                    // Reverse direction if we're doing a reverse sort
+                    if (keyA < keyB) {
+                        return -1 * currentSort.direction;
+                    }
+
+                    if (keyA > keyB) {
+                        return 1 * currentSort.direction;
+                    }
+
+                    return 0;
+                } else {
+                    // Reverse columns if we're doing a reverse sort
+                    if (currentSort.direction === 1) {
+                        return this._sortable[currentSort.column](keyA, keyB);
+                    } else {
+                        return this._sortable[currentSort.column](keyB, keyA);
+                    }
+                }
+            }.bind(this));
+        },
+        onSort: function(column) {
+            // Don't perform sort on unsortable columns
+            if (typeof(this._sortable[column]) === 'undefined') {
+                return;
+            }
+
+            var currentSort = this.state.currentSort;
+
+            if (currentSort.column === column) {
+                currentSort.direction *= -1;
+            } else {
+                currentSort.column = column;
+                currentSort.direction = 1;
+            }
+
+            // Set the current sort and pass it to the sort function
+            this.setState({ currentSort: currentSort });
+            this.sortByCurrentSort();
+        },
+        render: function() {
+            var children = [];
+            var columns;
+            var userColumnsSpecified = false;
+
+            if (
+                this.props.children &&
+                    this.props.children.length > 0 &&
+                        this.props.children[0].type.ConvenienceConstructor === Thead
+            ) {
+                columns = this.props.children[0].getColumns();
+            } else {
+                columns = this.props.columns || [];
+            }
+
+            if (columns.length > 0) {
+                userColumnsSpecified = true;
+                columns = this.translateColumnsArray(columns);
+            }
+
+            // Build up table rows
+            if (this.data && typeof this.data.map === 'function') {
+                // Build up the columns array
+                children = children.concat(this.data.map(function(rawData, i) {
+                    var data = rawData;
+                    var props = {};
+                    if (rawData.__reactableMeta === true) {
+                        data = rawData.data;
+                        props = rawData.props;
+                    }
+
+                    // Loop through the keys in each data row and build a td for it
+                    for (var k in data) {
+                        if (data.hasOwnProperty(k)) {
+                            // Update the columns array with the data's keys if columns were not
+                            // already specified
+                            if (userColumnsSpecified === false) {
+                                var column = {
+                                    key:   k,
+                                    label: k
+                                };
+
+                                // Only add a new column if it doesn't already exist in the columns array
+                                if (
+                                    columns.find(function(element) {
+                                    return element.key === column.key;
+                                }) === undefined
+                                ) {
+                                    columns.push(column);
+                                }
+                            }
+                        }
+                    }
+
+                    return (
+                        React.createElement(Tr, React.__spread({columns: columns, key: i, data: data},  props))
+                    );
+                }.bind(this)));
+            }
+
+            if (this.props.sortable === true) {
+                for (var i = 0; i < columns.length; i++) {
+                    this._sortable[columns[i].key] = 'default';
+                }
+            }
+
+            // Determine if we render the filter box
+            var filtering = false;
+            if (
+                this.props.filterable &&
+                    Array.isArray(this.props.filterable) &&
+                        this.props.filterable.length > 0
+            ) {
+                filtering = true;
+            }
+
+            // Apply filters
+            var filteredChildren = children;
+            if (this.state.filter !== '') {
+                filteredChildren = this.applyFilter(this.state.filter, filteredChildren);
+            }
+
+            // Determine pagination properties and which columns to display
+            var itemsPerPage = 0;
+            var pagination = false;
+            var numPages;
+            var currentPage = this.state.currentPage;
+
+            var currentChildren = filteredChildren;
+            if (this.props.itemsPerPage > 0) {
+                itemsPerPage = this.props.itemsPerPage;
+                numPages = Math.ceil(filteredChildren.length / itemsPerPage);
+
+                if (currentPage > numPages - 1) {
+                    currentPage = numPages - 1;
+                }
+
+                pagination = true;
+                currentChildren = filteredChildren.slice(
+                    currentPage * itemsPerPage,
+                    (currentPage + 1) * itemsPerPage
+                );
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return React.createElement("table", React.__spread({},  props), [
+                (columns && columns.length > 0 ?
+                 React.createElement(Thead, {columns: columns, 
+                     filtering: filtering, 
+                     onFilter: this.filterBy, 
+                     filterPlaceholder: this.props.filterPlaceholder, 
+                     currentFilter: this.state.filter, 
+                     sort: this.state.currentSort, 
+                     sortableColumns: this._sortable, 
+                     onSort: this.onSort, 
+                     key: "thead"})
+                 : null
+                ),
+                React.createElement("tbody", {className: "reactable-data", key: "tbody"}, 
+                    currentChildren
+                ),
+                (pagination === true ?
+                 React.createElement(Paginator, {colSpan: columns.length, 
+                     numPages: numPages, 
+                     currentPage: currentPage, 
+                     onPageChange: this.onPageChange, 
+                     key: "paginator"})
+                 : null
+                )
+            ]);
+        }
+    });
+
+    function toArray(obj) {
+        var ret = [];
+        for (var attr in obj) {
+            ret[attr] = obj;
+        }
+
+        return ret;
+    }
+
+    function filterPropsFrom(baseProps) {
+        baseProps = baseProps || {};
+        var props = {};
+        for (var key in baseProps) {
+            if (!(key in internalProps)) {
+                props[key] = baseProps[key];
+            }
+        }
+        return props;
+    }
+
+    function extractDataFrom(key, column) {
+        var value;
+        if (
+            typeof(key) !== 'undefined' &&
+                key !== null &&
+                    key.__reactableMeta === true
+        ) {
+            value = key.data[column];
+        } else {
+            value = key[column];
+        }
+
+        if (
+            typeof(value) !== 'undefined' &&
+                value !== null &&
+                    value.__reactableMeta === true
+        ) {
+            value = (typeof(value.props.value) !== 'undefined' && value.props.value !== null) ?
+                value.props.value : value.value;
+        }
+
+        return value;
+    }
+
+    var internalProps = {
+        columns: true,
+        sortable: true,
+        filterable: true,
+        sortBy: true,
+        defaultSort: true,
+        itemsPerPage: true,
+        childNode: true,
+        data: true,
+        children: true
+    };
+
+    return exports;
+}));
diff --git a/webcore/test/TC/require.js b/webcore/test/TC/require.js
new file mode 100644
index 0000000..bc43457
--- /dev/null
+++ b/webcore/test/TC/require.js
@@ -0,0 +1,2083 @@
+/** vim: et:ts=4:sw=4:sts=4
+ * @license RequireJS 2.1.16 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+//Not using strict: uneven strict support in browsers, #392, and causes
+//problems with requirejs.exec()/transpiler plugins that may not be strict.
+/*jslint regexp: true, nomen: true, sloppy: true */
+/*global window, navigator, document, importScripts, setTimeout, opera */
+
+var requirejs, require, define;
+(function (global) {
+    var req, s, head, baseElement, dataMain, src,
+        interactiveScript, currentlyAddingScript, mainScript, subPath,
+        version = '2.1.16',
+        commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
+        cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
+        jsSuffixRegExp = /\.js$/,
+        currDirRegExp = /^\.\//,
+        op = Object.prototype,
+        ostring = op.toString,
+        hasOwn = op.hasOwnProperty,
+        ap = Array.prototype,
+        apsp = ap.splice,
+        isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
+        isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
+        //PS3 indicates loaded and complete, but need to wait for complete
+        //specifically. Sequence is 'loading', 'loaded', execution,
+        // then 'complete'. The UA check is unfortunate, but not sure how
+        //to feature test w/o causing perf issues.
+        readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
+                      /^complete$/ : /^(complete|loaded)$/,
+        defContextName = '_',
+        //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
+        isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
+        contexts = {},
+        cfg = {},
+        globalDefQueue = [],
+        useInteractive = false;
+
+    function isFunction(it) {
+        return ostring.call(it) === '[object Function]';
+    }
+
+    function isArray(it) {
+        return ostring.call(it) === '[object Array]';
+    }
+
+    /**
+     * Helper function for iterating over an array. If the func returns
+     * a true value, it will break out of the loop.
+     */
+    function each(ary, func) {
+        if (ary) {
+            var i;
+            for (i = 0; i < ary.length; i += 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function for iterating over an array backwards. If the func
+     * returns a true value, it will break out of the loop.
+     */
+    function eachReverse(ary, func) {
+        if (ary) {
+            var i;
+            for (i = ary.length - 1; i > -1; i -= 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    function hasProp(obj, prop) {
+        return hasOwn.call(obj, prop);
+    }
+
+    function getOwn(obj, prop) {
+        return hasProp(obj, prop) && obj[prop];
+    }
+
+    /**
+     * Cycles over properties in an object and calls a function for each
+     * property value. If the function returns a truthy value, then the
+     * iteration is stopped.
+     */
+    function eachProp(obj, func) {
+        var prop;
+        for (prop in obj) {
+            if (hasProp(obj, prop)) {
+                if (func(obj[prop], prop)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Simple function to mix in properties from source into target,
+     * but only if target does not already have a property of the same name.
+     */
+    function mixin(target, source, force, deepStringMixin) {
+        if (source) {
+            eachProp(source, function (value, prop) {
+                if (force || !hasProp(target, prop)) {
+                    if (deepStringMixin && typeof value === 'object' && value &&
+                        !isArray(value) && !isFunction(value) &&
+                        !(value instanceof RegExp)) {
+
+                        if (!target[prop]) {
+                            target[prop] = {};
+                        }
+                        mixin(target[prop], value, force, deepStringMixin);
+                    } else {
+                        target[prop] = value;
+                    }
+                }
+            });
+        }
+        return target;
+    }
+
+    //Similar to Function.prototype.bind, but the 'this' object is specified
+    //first, since it is easier to read/figure out what 'this' will be.
+    function bind(obj, fn) {
+        return function () {
+            return fn.apply(obj, arguments);
+        };
+    }
+
+    function scripts() {
+        return document.getElementsByTagName('script');
+    }
+
+    function defaultOnError(err) {
+        throw err;
+    }
+
+    //Allow getting a global that is expressed in
+    //dot notation, like 'a.b.c'.
+    function getGlobal(value) {
+        if (!value) {
+            return value;
+        }
+        var g = global;
+        each(value.split('.'), function (part) {
+            g = g[part];
+        });
+        return g;
+    }
+
+    /**
+     * Constructs an error with a pointer to an URL with more information.
+     * @param {String} id the error ID that maps to an ID on a web page.
+     * @param {String} message human readable error.
+     * @param {Error} [err] the original error, if there is one.
+     *
+     * @returns {Error}
+     */
+    function makeError(id, msg, err, requireModules) {
+        var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
+        e.requireType = id;
+        e.requireModules = requireModules;
+        if (err) {
+            e.originalError = err;
+        }
+        return e;
+    }
+
+    if (typeof define !== 'undefined') {
+        //If a define is already in play via another AMD loader,
+        //do not overwrite.
+        return;
+    }
+
+    if (typeof requirejs !== 'undefined') {
+        if (isFunction(requirejs)) {
+            //Do not overwrite an existing requirejs instance.
+            return;
+        }
+        cfg = requirejs;
+        requirejs = undefined;
+    }
+
+    //Allow for a require config object
+    if (typeof require !== 'undefined' && !isFunction(require)) {
+        //assume it is a config object.
+        cfg = require;
+        require = undefined;
+    }
+
+    function newContext(contextName) {
+        var inCheckLoaded, Module, context, handlers,
+            checkLoadedTimeoutId,
+            config = {
+                //Defaults. Do not set a default for map
+                //config to speed up normalize(), which
+                //will run faster if there is no default.
+                waitSeconds: 7,
+                baseUrl: './',
+                paths: {},
+                bundles: {},
+                pkgs: {},
+                shim: {},
+                config: {}
+            },
+            registry = {},
+            //registry of just enabled modules, to speed
+            //cycle breaking code when lots of modules
+            //are registered, but not activated.
+            enabledRegistry = {},
+            undefEvents = {},
+            defQueue = [],
+            defined = {},
+            urlFetched = {},
+            bundlesMap = {},
+            requireCounter = 1,
+            unnormalizedCounter = 1;
+
+        /**
+         * Trims the . and .. from an array of path segments.
+         * It will keep a leading path segment if a .. will become
+         * the first path segment, to help with module name lookups,
+         * which act like paths, but can be remapped. But the end result,
+         * all paths that use this function should look normalized.
+         * NOTE: this method MODIFIES the input array.
+         * @param {Array} ary the array of path segments.
+         */
+        function trimDots(ary) {
+            var i, part;
+            for (i = 0; i < ary.length; i++) {
+                part = ary[i];
+                if (part === '.') {
+                    ary.splice(i, 1);
+                    i -= 1;
+                } else if (part === '..') {
+                    // If at the start, or previous value is still ..,
+                    // keep them so that when converted to a path it may
+                    // still work when converted to a path, even though
+                    // as an ID it is less than ideal. In larger point
+                    // releases, may be better to just kick out an error.
+                    if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') {
+                        continue;
+                    } else if (i > 0) {
+                        ary.splice(i - 1, 2);
+                        i -= 2;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Given a relative module name, like ./something, normalize it to
+         * a real name that can be mapped to a path.
+         * @param {String} name the relative name
+         * @param {String} baseName a real name that the name arg is relative
+         * to.
+         * @param {Boolean} applyMap apply the map config to the value. Should
+         * only be done if this normalization is for a dependency ID.
+         * @returns {String} normalized name
+         */
+        function normalize(name, baseName, applyMap) {
+            var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
+                foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
+                baseParts = (baseName && baseName.split('/')),
+                map = config.map,
+                starMap = map && map['*'];
+
+            //Adjust any relative paths.
+            if (name) {
+                name = name.split('/');
+                lastIndex = name.length - 1;
+
+                // If wanting node ID compatibility, strip .js from end
+                // of IDs. Have to do this here, and not in nameToUrl
+                // because node allows either .js or non .js to map
+                // to same file.
+                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+                }
+
+                // Starts with a '.' so need the baseName
+                if (name[0].charAt(0) === '.' && baseParts) {
+                    //Convert baseName to array, and lop off the last part,
+                    //so that . matches that 'directory' and not name of the baseName's
+                    //module. For instance, baseName of 'one/two/three', maps to
+                    //'one/two/three.js', but we want the directory, 'one/two' for
+                    //this normalization.
+                    normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
+                    name = normalizedBaseParts.concat(name);
+                }
+
+                trimDots(name);
+                name = name.join('/');
+            }
+
+            //Apply map config if available.
+            if (applyMap && map && (baseParts || starMap)) {
+                nameParts = name.split('/');
+
+                outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
+                    nameSegment = nameParts.slice(0, i).join('/');
+
+                    if (baseParts) {
+                        //Find the longest baseName segment match in the config.
+                        //So, do joins on the biggest to smallest lengths of baseParts.
+                        for (j = baseParts.length; j > 0; j -= 1) {
+                            mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
+
+                            //baseName segment has config, find if it has one for
+                            //this name.
+                            if (mapValue) {
+                                mapValue = getOwn(mapValue, nameSegment);
+                                if (mapValue) {
+                                    //Match, update name to the new value.
+                                    foundMap = mapValue;
+                                    foundI = i;
+                                    break outerLoop;
+                                }
+                            }
+                        }
+                    }
+
+                    //Check for a star map match, but just hold on to it,
+                    //if there is a shorter segment match later in a matching
+                    //config, then favor over this star map.
+                    if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
+                        foundStarMap = getOwn(starMap, nameSegment);
+                        starI = i;
+                    }
+                }
+
+                if (!foundMap && foundStarMap) {
+                    foundMap = foundStarMap;
+                    foundI = starI;
+                }
+
+                if (foundMap) {
+                    nameParts.splice(0, foundI, foundMap);
+                    name = nameParts.join('/');
+                }
+            }
+
+            // If the name points to a package's name, use
+            // the package main instead.
+            pkgMain = getOwn(config.pkgs, name);
+
+            return pkgMain ? pkgMain : name;
+        }
+
+        function removeScript(name) {
+            if (isBrowser) {
+                each(scripts(), function (scriptNode) {
+                    if (scriptNode.getAttribute('data-requiremodule') === name &&
+                            scriptNode.getAttribute('data-requirecontext') === context.contextName) {
+                        scriptNode.parentNode.removeChild(scriptNode);
+                        return true;
+                    }
+                });
+            }
+        }
+
+        function hasPathFallback(id) {
+            var pathConfig = getOwn(config.paths, id);
+            if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
+                //Pop off the first array value, since it failed, and
+                //retry
+                pathConfig.shift();
+                context.require.undef(id);
+
+                //Custom require that does not do map translation, since
+                //ID is "absolute", already mapped/resolved.
+                context.makeRequire(null, {
+                    skipMap: true
+                })([id]);
+
+                return true;
+            }
+        }
+
+        //Turns a plugin!resource to [plugin, resource]
+        //with the plugin being undefined if the name
+        //did not have a plugin prefix.
+        function splitPrefix(name) {
+            var prefix,
+                index = name ? name.indexOf('!') : -1;
+            if (index > -1) {
+                prefix = name.substring(0, index);
+                name = name.substring(index + 1, name.length);
+            }
+            return [prefix, name];
+        }
+
+        /**
+         * Creates a module mapping that includes plugin prefix, module
+         * name, and path. If parentModuleMap is provided it will
+         * also normalize the name via require.normalize()
+         *
+         * @param {String} name the module name
+         * @param {String} [parentModuleMap] parent module map
+         * for the module name, used to resolve relative names.
+         * @param {Boolean} isNormalized: is the ID already normalized.
+         * This is true if this call is done for a define() module ID.
+         * @param {Boolean} applyMap: apply the map config to the ID.
+         * Should only be true if this map is for a dependency.
+         *
+         * @returns {Object}
+         */
+        function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
+            var url, pluginModule, suffix, nameParts,
+                prefix = null,
+                parentName = parentModuleMap ? parentModuleMap.name : null,
+                originalName = name,
+                isDefine = true,
+                normalizedName = '';
+
+            //If no name, then it means it is a require call, generate an
+            //internal name.
+            if (!name) {
+                isDefine = false;
+                name = '_ at r' + (requireCounter += 1);
+            }
+
+            nameParts = splitPrefix(name);
+            prefix = nameParts[0];
+            name = nameParts[1];
+
+            if (prefix) {
+                prefix = normalize(prefix, parentName, applyMap);
+                pluginModule = getOwn(defined, prefix);
+            }
+
+            //Account for relative paths if there is a base name.
+            if (name) {
+                if (prefix) {
+                    if (pluginModule && pluginModule.normalize) {
+                        //Plugin is loaded, use its normalize method.
+                        normalizedName = pluginModule.normalize(name, function (name) {
+                            return normalize(name, parentName, applyMap);
+                        });
+                    } else {
+                        // If nested plugin references, then do not try to
+                        // normalize, as it will not normalize correctly. This
+                        // places a restriction on resourceIds, and the longer
+                        // term solution is not to normalize until plugins are
+                        // loaded and all normalizations to allow for async
+                        // loading of a loader plugin. But for now, fixes the
+                        // common uses. Details in #1131
+                        normalizedName = name.indexOf('!') === -1 ?
+                                         normalize(name, parentName, applyMap) :
+                                         name;
+                    }
+                } else {
+                    //A regular module.
+                    normalizedName = normalize(name, parentName, applyMap);
+
+                    //Normalized name may be a plugin ID due to map config
+                    //application in normalize. The map config values must
+                    //already be normalized, so do not need to redo that part.
+                    nameParts = splitPrefix(normalizedName);
+                    prefix = nameParts[0];
+                    normalizedName = nameParts[1];
+                    isNormalized = true;
+
+                    url = context.nameToUrl(normalizedName);
+                }
+            }
+
+            //If the id is a plugin id that cannot be determined if it needs
+            //normalization, stamp it with a unique ID so two matching relative
+            //ids that may conflict can be separate.
+            suffix = prefix && !pluginModule && !isNormalized ?
+                     '_unnormalized' + (unnormalizedCounter += 1) :
+                     '';
+
+            return {
+                prefix: prefix,
+                name: normalizedName,
+                parentMap: parentModuleMap,
+                unnormalized: !!suffix,
+                url: url,
+                originalName: originalName,
+                isDefine: isDefine,
+                id: (prefix ?
+                        prefix + '!' + normalizedName :
+                        normalizedName) + suffix
+            };
+        }
+
+        function getModule(depMap) {
+            var id = depMap.id,
+                mod = getOwn(registry, id);
+
+            if (!mod) {
+                mod = registry[id] = new context.Module(depMap);
+            }
+
+            return mod;
+        }
+
+        function on(depMap, name, fn) {
+            var id = depMap.id,
+                mod = getOwn(registry, id);
+
+            if (hasProp(defined, id) &&
+                    (!mod || mod.defineEmitComplete)) {
+                if (name === 'defined') {
+                    fn(defined[id]);
+                }
+            } else {
+                mod = getModule(depMap);
+                if (mod.error && name === 'error') {
+                    fn(mod.error);
+                } else {
+                    mod.on(name, fn);
+                }
+            }
+        }
+
+        function onError(err, errback) {
+            var ids = err.requireModules,
+                notified = false;
+
+            if (errback) {
+                errback(err);
+            } else {
+                each(ids, function (id) {
+                    var mod = getOwn(registry, id);
+                    if (mod) {
+                        //Set error on module, so it skips timeout checks.
+                        mod.error = err;
+                        if (mod.events.error) {
+                            notified = true;
+                            mod.emit('error', err);
+                        }
+                    }
+                });
+
+                if (!notified) {
+                    req.onError(err);
+                }
+            }
+        }
+
+        /**
+         * Internal method to transfer globalQueue items to this context's
+         * defQueue.
+         */
+        function takeGlobalQueue() {
+            //Push all the globalDefQueue items into the context's defQueue
+            if (globalDefQueue.length) {
+                //Array splice in the values since the context code has a
+                //local var ref to defQueue, so cannot just reassign the one
+                //on context.
+                apsp.apply(defQueue,
+                           [defQueue.length, 0].concat(globalDefQueue));
+                globalDefQueue = [];
+            }
+        }
+
+        handlers = {
+            'require': function (mod) {
+                if (mod.require) {
+                    return mod.require;
+                } else {
+                    return (mod.require = context.makeRequire(mod.map));
+                }
+            },
+            'exports': function (mod) {
+                mod.usingExports = true;
+                if (mod.map.isDefine) {
+                    if (mod.exports) {
+                        return (defined[mod.map.id] = mod.exports);
+                    } else {
+                        return (mod.exports = defined[mod.map.id] = {});
+                    }
+                }
+            },
+            'module': function (mod) {
+                if (mod.module) {
+                    return mod.module;
+                } else {
+                    return (mod.module = {
+                        id: mod.map.id,
+                        uri: mod.map.url,
+                        config: function () {
+                            return  getOwn(config.config, mod.map.id) || {};
+                        },
+                        exports: mod.exports || (mod.exports = {})
+                    });
+                }
+            }
+        };
+
+        function cleanRegistry(id) {
+            //Clean up machinery used for waiting modules.
+            delete registry[id];
+            delete enabledRegistry[id];
+        }
+
+        function breakCycle(mod, traced, processed) {
+            var id = mod.map.id;
+
+            if (mod.error) {
+                mod.emit('error', mod.error);
+            } else {
+                traced[id] = true;
+                each(mod.depMaps, function (depMap, i) {
+                    var depId = depMap.id,
+                        dep = getOwn(registry, depId);
+
+                    //Only force things that have not completed
+                    //being defined, so still in the registry,
+                    //and only if it has not been matched up
+                    //in the module already.
+                    if (dep && !mod.depMatched[i] && !processed[depId]) {
+                        if (getOwn(traced, depId)) {
+                            mod.defineDep(i, defined[depId]);
+                            mod.check(); //pass false?
+                        } else {
+                            breakCycle(dep, traced, processed);
+                        }
+                    }
+                });
+                processed[id] = true;
+            }
+        }
+
+        function checkLoaded() {
+            var err, usingPathFallback,
+                waitInterval = config.waitSeconds * 1000,
+                //It is possible to disable the wait interval by using waitSeconds of 0.
+                expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
+                noLoads = [],
+                reqCalls = [],
+                stillLoading = false,
+                needCycleCheck = true;
+
+            //Do not bother if this call was a result of a cycle break.
+            if (inCheckLoaded) {
+                return;
+            }
+
+            inCheckLoaded = true;
+
+            //Figure out the state of all the modules.
+            eachProp(enabledRegistry, function (mod) {
+                var map = mod.map,
+                    modId = map.id;
+
+                //Skip things that are not enabled or in error state.
+                if (!mod.enabled) {
+                    return;
+                }
+
+                if (!map.isDefine) {
+                    reqCalls.push(mod);
+                }
+
+                if (!mod.error) {
+                    //If the module should be executed, and it has not
+                    //been inited and time is up, remember it.
+                    if (!mod.inited && expired) {
+                        if (hasPathFallback(modId)) {
+                            usingPathFallback = true;
+                            stillLoading = true;
+                        } else {
+                            noLoads.push(modId);
+                            removeScript(modId);
+                        }
+                    } else if (!mod.inited && mod.fetched && map.isDefine) {
+                        stillLoading = true;
+                        if (!map.prefix) {
+                            //No reason to keep looking for unfinished
+                            //loading. If the only stillLoading is a
+                            //plugin resource though, keep going,
+                            //because it may be that a plugin resource
+                            //is waiting on a non-plugin cycle.
+                            return (needCycleCheck = false);
+                        }
+                    }
+                }
+            });
+
+            if (expired && noLoads.length) {
+                //If wait time expired, throw error of unloaded modules.
+                err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
+                err.contextName = context.contextName;
+                return onError(err);
+            }
+
+            //Not expired, check for a cycle.
+            if (needCycleCheck) {
+                each(reqCalls, function (mod) {
+                    breakCycle(mod, {}, {});
+                });
+            }
+
+            //If still waiting on loads, and the waiting load is something
+            //other than a plugin resource, or there are still outstanding
+            //scripts, then just try back later.
+            if ((!expired || usingPathFallback) && stillLoading) {
+                //Something is still waiting to load. Wait for it, but only
+                //if a timeout is not already in effect.
+                if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
+                    checkLoadedTimeoutId = setTimeout(function () {
+                        checkLoadedTimeoutId = 0;
+                        checkLoaded();
+                    }, 50);
+                }
+            }
+
+            inCheckLoaded = false;
+        }
+
+        Module = function (map) {
+            this.events = getOwn(undefEvents, map.id) || {};
+            this.map = map;
+            this.shim = getOwn(config.shim, map.id);
+            this.depExports = [];
+            this.depMaps = [];
+            this.depMatched = [];
+            this.pluginMaps = {};
+            this.depCount = 0;
+
+            /* this.exports this.factory
+               this.depMaps = [],
+               this.enabled, this.fetched
+            */
+        };
+
+        Module.prototype = {
+            init: function (depMaps, factory, errback, options) {
+                options = options || {};
+
+                //Do not do more inits if already done. Can happen if there
+                //are multiple define calls for the same module. That is not
+                //a normal, common case, but it is also not unexpected.
+                if (this.inited) {
+                    return;
+                }
+
+                this.factory = factory;
+
+                if (errback) {
+                    //Register for errors on this module.
+                    this.on('error', errback);
+                } else if (this.events.error) {
+                    //If no errback already, but there are error listeners
+                    //on this module, set up an errback to pass to the deps.
+                    errback = bind(this, function (err) {
+                        this.emit('error', err);
+                    });
+                }
+
+                //Do a copy of the dependency array, so that
+                //source inputs are not modified. For example
+                //"shim" deps are passed in here directly, and
+                //doing a direct modification of the depMaps array
+                //would affect that config.
+                this.depMaps = depMaps && depMaps.slice(0);
+
+                this.errback = errback;
+
+                //Indicate this module has be initialized
+                this.inited = true;
+
+                this.ignore = options.ignore;
+
+                //Could have option to init this module in enabled mode,
+                //or could have been previously marked as enabled. However,
+                //the dependencies are not known until init is called. So
+                //if enabled previously, now trigger dependencies as enabled.
+                if (options.enabled || this.enabled) {
+                    //Enable this module and dependencies.
+                    //Will call this.check()
+                    this.enable();
+                } else {
+                    this.check();
+                }
+            },
+
+            defineDep: function (i, depExports) {
+                //Because of cycles, defined callback for a given
+                //export can be called more than once.
+                if (!this.depMatched[i]) {
+                    this.depMatched[i] = true;
+                    this.depCount -= 1;
+                    this.depExports[i] = depExports;
+                }
+            },
+
+            fetch: function () {
+                if (this.fetched) {
+                    return;
+                }
+                this.fetched = true;
+
+                context.startTime = (new Date()).getTime();
+
+                var map = this.map;
+
+                //If the manager is for a plugin managed resource,
+                //ask the plugin to load it now.
+                if (this.shim) {
+                    context.makeRequire(this.map, {
+                        enableBuildCallback: true
+                    })(this.shim.deps || [], bind(this, function () {
+                        return map.prefix ? this.callPlugin() : this.load();
+                    }));
+                } else {
+                    //Regular dependency.
+                    return map.prefix ? this.callPlugin() : this.load();
+                }
+            },
+
+            load: function () {
+                var url = this.map.url;
+
+                //Regular dependency.
+                if (!urlFetched[url]) {
+                    urlFetched[url] = true;
+                    context.load(this.map.id, url);
+                }
+            },
+
+            /**
+             * Checks if the module is ready to define itself, and if so,
+             * define it.
+             */
+            check: function () {
+                if (!this.enabled || this.enabling) {
+                    return;
+                }
+
+                var err, cjsModule,
+                    id = this.map.id,
+                    depExports = this.depExports,
+                    exports = this.exports,
+                    factory = this.factory;
+
+                if (!this.inited) {
+                    this.fetch();
+                } else if (this.error) {
+                    this.emit('error', this.error);
+                } else if (!this.defining) {
+                    //The factory could trigger another require call
+                    //that would result in checking this module to
+                    //define itself again. If already in the process
+                    //of doing that, skip this work.
+                    this.defining = true;
+
+                    if (this.depCount < 1 && !this.defined) {
+                        if (isFunction(factory)) {
+                            //If there is an error listener, favor passing
+                            //to that instead of throwing an error. However,
+                            //only do it for define()'d  modules. require
+                            //errbacks should not be called for failures in
+                            //their callbacks (#699). However if a global
+                            //onError is set, use that.
+                            if ((this.events.error && this.map.isDefine) ||
+                                req.onError !== defaultOnError) {
+                                try {
+                                    exports = context.execCb(id, factory, depExports, exports);
+                                } catch (e) {
+                                    err = e;
+                                }
+                            } else {
+                                exports = context.execCb(id, factory, depExports, exports);
+                            }
+
+                            // Favor return value over exports. If node/cjs in play,
+                            // then will not have a return value anyway. Favor
+                            // module.exports assignment over exports object.
+                            if (this.map.isDefine && exports === undefined) {
+                                cjsModule = this.module;
+                                if (cjsModule) {
+                                    exports = cjsModule.exports;
+                                } else if (this.usingExports) {
+                                    //exports already set the defined value.
+                                    exports = this.exports;
+                                }
+                            }
+
+                            if (err) {
+                                err.requireMap = this.map;
+                                err.requireModules = this.map.isDefine ? [this.map.id] : null;
+                                err.requireType = this.map.isDefine ? 'define' : 'require';
+                                return onError((this.error = err));
+                            }
+
+                        } else {
+                            //Just a literal value
+                            exports = factory;
+                        }
+
+                        this.exports = exports;
+
+                        if (this.map.isDefine && !this.ignore) {
+                            defined[id] = exports;
+
+                            if (req.onResourceLoad) {
+                                req.onResourceLoad(context, this.map, this.depMaps);
+                            }
+                        }
+
+                        //Clean up
+                        cleanRegistry(id);
+
+                        this.defined = true;
+                    }
+
+                    //Finished the define stage. Allow calling check again
+                    //to allow define notifications below in the case of a
+                    //cycle.
+                    this.defining = false;
+
+                    if (this.defined && !this.defineEmitted) {
+                        this.defineEmitted = true;
+                        this.emit('defined', this.exports);
+                        this.defineEmitComplete = true;
+                    }
+
+                }
+            },
+
+            callPlugin: function () {
+                var map = this.map,
+                    id = map.id,
+                    //Map already normalized the prefix.
+                    pluginMap = makeModuleMap(map.prefix);
+
+                //Mark this as a dependency for this plugin, so it
+                //can be traced for cycles.
+                this.depMaps.push(pluginMap);
+
+                on(pluginMap, 'defined', bind(this, function (plugin) {
+                    var load, normalizedMap, normalizedMod,
+                        bundleId = getOwn(bundlesMap, this.map.id),
+                        name = this.map.name,
+                        parentName = this.map.parentMap ? this.map.parentMap.name : null,
+                        localRequire = context.makeRequire(map.parentMap, {
+                            enableBuildCallback: true
+                        });
+
+                    //If current map is not normalized, wait for that
+                    //normalized name to load instead of continuing.
+                    if (this.map.unnormalized) {
+                        //Normalize the ID if the plugin allows it.
+                        if (plugin.normalize) {
+                            name = plugin.normalize(name, function (name) {
+                                return normalize(name, parentName, true);
+                            }) || '';
+                        }
+
+                        //prefix and name should already be normalized, no need
+                        //for applying map config again either.
+                        normalizedMap = makeModuleMap(map.prefix + '!' + name,
+                                                      this.map.parentMap);
+                        on(normalizedMap,
+                            'defined', bind(this, function (value) {
+                                this.init([], function () { return value; }, null, {
+                                    enabled: true,
+                                    ignore: true
+                                });
+                            }));
+
+                        normalizedMod = getOwn(registry, normalizedMap.id);
+                        if (normalizedMod) {
+                            //Mark this as a dependency for this plugin, so it
+                            //can be traced for cycles.
+                            this.depMaps.push(normalizedMap);
+
+                            if (this.events.error) {
+                                normalizedMod.on('error', bind(this, function (err) {
+                                    this.emit('error', err);
+                                }));
+                            }
+                            normalizedMod.enable();
+                        }
+
+                        return;
+                    }
+
+                    //If a paths config, then just load that file instead to
+                    //resolve the plugin, as it is built into that paths layer.
+                    if (bundleId) {
+                        this.map.url = context.nameToUrl(bundleId);
+                        this.load();
+                        return;
+                    }
+
+                    load = bind(this, function (value) {
+                        this.init([], function () { return value; }, null, {
+                            enabled: true
+                        });
+                    });
+
+                    load.error = bind(this, function (err) {
+                        this.inited = true;
+                        this.error = err;
+                        err.requireModules = [id];
+
+                        //Remove temp unnormalized modules for this module,
+                        //since they will never be resolved otherwise now.
+                        eachProp(registry, function (mod) {
+                            if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
+                                cleanRegistry(mod.map.id);
+                            }
+                        });
+
+                        onError(err);
+                    });
+
+                    //Allow plugins to load other code without having to know the
+                    //context or how to 'complete' the load.
+                    load.fromText = bind(this, function (text, textAlt) {
+                        /*jslint evil: true */
+                        var moduleName = map.name,
+                            moduleMap = makeModuleMap(moduleName),
+                            hasInteractive = useInteractive;
+
+                        //As of 2.1.0, support just passing the text, to reinforce
+                        //fromText only being called once per resource. Still
+                        //support old style of passing moduleName but discard
+                        //that moduleName in favor of the internal ref.
+                        if (textAlt) {
+                            text = textAlt;
+                        }
+
+                        //Turn off interactive script matching for IE for any define
+                        //calls in the text, then turn it back on at the end.
+                        if (hasInteractive) {
+                            useInteractive = false;
+                        }
+
+                        //Prime the system by creating a module instance for
+                        //it.
+                        getModule(moduleMap);
+
+                        //Transfer any config to this other module.
+                        if (hasProp(config.config, id)) {
+                            config.config[moduleName] = config.config[id];
+                        }
+
+                        try {
+                            req.exec(text);
+                        } catch (e) {
+                            return onError(makeError('fromtexteval',
+                                             'fromText eval for ' + id +
+                                            ' failed: ' + e,
+                                             e,
+                                             [id]));
+                        }
+
+                        if (hasInteractive) {
+                            useInteractive = true;
+                        }
+
+                        //Mark this as a dependency for the plugin
+                        //resource
+                        this.depMaps.push(moduleMap);
+
+                        //Support anonymous modules.
+                        context.completeLoad(moduleName);
+
+                        //Bind the value of that module to the value for this
+                        //resource ID.
+                        localRequire([moduleName], load);
+                    });
+
+                    //Use parentName here since the plugin's name is not reliable,
+                    //could be some weird string with no path that actually wants to
+                    //reference the parentName's path.
+                    plugin.load(map.name, localRequire, load, config);
+                }));
+
+                context.enable(pluginMap, this);
+                this.pluginMaps[pluginMap.id] = pluginMap;
+            },
+
+            enable: function () {
+                enabledRegistry[this.map.id] = this;
+                this.enabled = true;
+
+                //Set flag mentioning that the module is enabling,
+                //so that immediate calls to the defined callbacks
+                //for dependencies do not trigger inadvertent load
+                //with the depCount still being zero.
+                this.enabling = true;
+
+                //Enable each dependency
+                each(this.depMaps, bind(this, function (depMap, i) {
+                    var id, mod, handler;
+
+                    if (typeof depMap === 'string') {
+                        //Dependency needs to be converted to a depMap
+                        //and wired up to this module.
+                        depMap = makeModuleMap(depMap,
+                                               (this.map.isDefine ? this.map : this.map.parentMap),
+                                               false,
+                                               !this.skipMap);
+                        this.depMaps[i] = depMap;
+
+                        handler = getOwn(handlers, depMap.id);
+
+                        if (handler) {
+                            this.depExports[i] = handler(this);
+                            return;
+                        }
+
+                        this.depCount += 1;
+
+                        on(depMap, 'defined', bind(this, function (depExports) {
+                            this.defineDep(i, depExports);
+                            this.check();
+                        }));
+
+                        if (this.errback) {
+                            on(depMap, 'error', bind(this, this.errback));
+                        } else if (this.events.error) {
+                            // No direct errback on this module, but something
+                            // else is listening for errors, so be sure to
+                            // propagate the error correctly.
+                            on(depMap, 'error', bind(this, function(err) {
+                                this.emit('error', err);
+                            }));
+                        }
+                    }
+
+                    id = depMap.id;
+                    mod = registry[id];
+
+                    //Skip special modules like 'require', 'exports', 'module'
+                    //Also, don't call enable if it is already enabled,
+                    //important in circular dependency cases.
+                    if (!hasProp(handlers, id) && mod && !mod.enabled) {
+                        context.enable(depMap, this);
+                    }
+                }));
+
+                //Enable each plugin that is used in
+                //a dependency
+                eachProp(this.pluginMaps, bind(this, function (pluginMap) {
+                    var mod = getOwn(registry, pluginMap.id);
+                    if (mod && !mod.enabled) {
+                        context.enable(pluginMap, this);
+                    }
+                }));
+
+                this.enabling = false;
+
+                this.check();
+            },
+
+            on: function (name, cb) {
+                var cbs = this.events[name];
+                if (!cbs) {
+                    cbs = this.events[name] = [];
+                }
+                cbs.push(cb);
+            },
+
+            emit: function (name, evt) {
+                each(this.events[name], function (cb) {
+                    cb(evt);
+                });
+                if (name === 'error') {
+                    //Now that the error handler was triggered, remove
+                    //the listeners, since this broken Module instance
+                    //can stay around for a while in the registry.
+                    delete this.events[name];
+                }
+            }
+        };
+
+        function callGetModule(args) {
+            //Skip modules already defined.
+            if (!hasProp(defined, args[0])) {
+                getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+            }
+        }
+
+        function removeListener(node, func, name, ieName) {
+            //Favor detachEvent because of IE9
+            //issue, see attachEvent/addEventListener comment elsewhere
+            //in this file.
+            if (node.detachEvent && !isOpera) {
+                //Probably IE. If not it will throw an error, which will be
+                //useful to know.
+                if (ieName) {
+                    node.detachEvent(ieName, func);
+                }
+            } else {
+                node.removeEventListener(name, func, false);
+            }
+        }
+
+        /**
+         * Given an event from a script node, get the requirejs info from it,
+         * and then removes the event listeners on the node.
+         * @param {Event} evt
+         * @returns {Object}
+         */
+        function getScriptData(evt) {
+            //Using currentTarget instead of target for Firefox 2.0's sake. Not
+            //all old browsers will be supported, but this one was easy enough
+            //to support and still makes sense.
+            var node = evt.currentTarget || evt.srcElement;
+
+            //Remove the listeners once here.
+            removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
+            removeListener(node, context.onScriptError, 'error');
+
+            return {
+                node: node,
+                id: node && node.getAttribute('data-requiremodule')
+            };
+        }
+
+        function intakeDefines() {
+            var args;
+
+            //Any defined modules in the global queue, intake them now.
+            takeGlobalQueue();
+
+            //Make sure any remaining defQueue items get properly processed.
+            while (defQueue.length) {
+                args = defQueue.shift();
+                if (args[0] === null) {
+                    return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+                } else {
+                    //args are id, deps, factory. Should be normalized by the
+                    //define() function.
+                    callGetModule(args);
+                }
+            }
+        }
+
+        context = {
+            config: config,
+            contextName: contextName,
+            registry: registry,
+            defined: defined,
+            urlFetched: urlFetched,
+            defQueue: defQueue,
+            Module: Module,
+            makeModuleMap: makeModuleMap,
+            nextTick: req.nextTick,
+            onError: onError,
+
+            /**
+             * Set a configuration for the context.
+             * @param {Object} cfg config object to integrate.
+             */
+            configure: function (cfg) {
+                //Make sure the baseUrl ends in a slash.
+                if (cfg.baseUrl) {
+                    if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
+                        cfg.baseUrl += '/';
+                    }
+                }
+
+                //Save off the paths since they require special processing,
+                //they are additive.
+                var shim = config.shim,
+                    objs = {
+                        paths: true,
+                        bundles: true,
+                        config: true,
+                        map: true
+                    };
+
+                eachProp(cfg, function (value, prop) {
+                    if (objs[prop]) {
+                        if (!config[prop]) {
+                            config[prop] = {};
+                        }
+                        mixin(config[prop], value, true, true);
+                    } else {
+                        config[prop] = value;
+                    }
+                });
+
+                //Reverse map the bundles
+                if (cfg.bundles) {
+                    eachProp(cfg.bundles, function (value, prop) {
+                        each(value, function (v) {
+                            if (v !== prop) {
+                                bundlesMap[v] = prop;
+                            }
+                        });
+                    });
+                }
+
+                //Merge shim
+                if (cfg.shim) {
+                    eachProp(cfg.shim, function (value, id) {
+                        //Normalize the structure
+                        if (isArray(value)) {
+                            value = {
+                                deps: value
+                            };
+                        }
+                        if ((value.exports || value.init) && !value.exportsFn) {
+                            value.exportsFn = context.makeShimExports(value);
+                        }
+                        shim[id] = value;
+                    });
+                    config.shim = shim;
+                }
+
+                //Adjust packages if necessary.
+                if (cfg.packages) {
+                    each(cfg.packages, function (pkgObj) {
+                        var location, name;
+
+                        pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
+
+                        name = pkgObj.name;
+                        location = pkgObj.location;
+                        if (location) {
+                            config.paths[name] = pkgObj.location;
+                        }
+
+                        //Save pointer to main module ID for pkg name.
+                        //Remove leading dot in main, so main paths are normalized,
+                        //and remove any trailing .js, since different package
+                        //envs have different conventions: some use a module name,
+                        //some use a file name.
+                        config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
+                                     .replace(currDirRegExp, '')
+                                     .replace(jsSuffixRegExp, '');
+                    });
+                }
+
+                //If there are any "waiting to execute" modules in the registry,
+                //update the maps for them, since their info, like URLs to load,
+                //may have changed.
+                eachProp(registry, function (mod, id) {
+                    //If module already has init called, since it is too
+                    //late to modify them, and ignore unnormalized ones
+                    //since they are transient.
+                    if (!mod.inited && !mod.map.unnormalized) {
+                        mod.map = makeModuleMap(id);
+                    }
+                });
+
+                //If a deps array or a config callback is specified, then call
+                //require with those args. This is useful when require is defined as a
+                //config object before require.js is loaded.
+                if (cfg.deps || cfg.callback) {
+                    context.require(cfg.deps || [], cfg.callback);
+                }
+            },
+
+            makeShimExports: function (value) {
+                function fn() {
+                    var ret;
+                    if (value.init) {
+                        ret = value.init.apply(global, arguments);
+                    }
+                    return ret || (value.exports && getGlobal(value.exports));
+                }
+                return fn;
+            },
+
+            makeRequire: function (relMap, options) {
+                options = options || {};
+
+                function localRequire(deps, callback, errback) {
+                    var id, map, requireMod;
+
+                    if (options.enableBuildCallback && callback && isFunction(callback)) {
+                        callback.__requireJsBuild = true;
+                    }
+
+                    if (typeof deps === 'string') {
+                        if (isFunction(callback)) {
+                            //Invalid call
+                            return onError(makeError('requireargs', 'Invalid require call'), errback);
+                        }
+
+                        //If require|exports|module are requested, get the
+                        //value for them from the special handlers. Caveat:
+                        //this only works while module is being defined.
+                        if (relMap && hasProp(handlers, deps)) {
+                            return handlers[deps](registry[relMap.id]);
+                        }
+
+                        //Synchronous access to one module. If require.get is
+                        //available (as in the Node adapter), prefer that.
+                        if (req.get) {
+                            return req.get(context, deps, relMap, localRequire);
+                        }
+
+                        //Normalize module name, if it contains . or ..
+                        map = makeModuleMap(deps, relMap, false, true);
+                        id = map.id;
+
+                        if (!hasProp(defined, id)) {
+                            return onError(makeError('notloaded', 'Module name "' +
+                                        id +
+                                        '" has not been loaded yet for context: ' +
+                                        contextName +
+                                        (relMap ? '' : '. Use require([])')));
+                        }
+                        return defined[id];
+                    }
+
+                    //Grab defines waiting in the global queue.
+                    intakeDefines();
+
+                    //Mark all the dependencies as needing to be loaded.
+                    context.nextTick(function () {
+                        //Some defines could have been added since the
+                        //require call, collect them.
+                        intakeDefines();
+
+                        requireMod = getModule(makeModuleMap(null, relMap));
+
+                        //Store if map config should be applied to this require
+                        //call for dependencies.
+                        requireMod.skipMap = options.skipMap;
+
+                        requireMod.init(deps, callback, errback, {
+                            enabled: true
+                        });
+
+                        checkLoaded();
+                    });
+
+                    return localRequire;
+                }
+
+                mixin(localRequire, {
+                    isBrowser: isBrowser,
+
+                    /**
+                     * Converts a module name + .extension into an URL path.
+                     * *Requires* the use of a module name. It does not support using
+                     * plain URLs like nameToUrl.
+                     */
+                    toUrl: function (moduleNamePlusExt) {
+                        var ext,
+                            index = moduleNamePlusExt.lastIndexOf('.'),
+                            segment = moduleNamePlusExt.split('/')[0],
+                            isRelative = segment === '.' || segment === '..';
+
+                        //Have a file extension alias, and it is not the
+                        //dots from a relative path.
+                        if (index !== -1 && (!isRelative || index > 1)) {
+                            ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
+                            moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
+                        }
+
+                        return context.nameToUrl(normalize(moduleNamePlusExt,
+                                                relMap && relMap.id, true), ext,  true);
+                    },
+
+                    defined: function (id) {
+                        return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
+                    },
+
+                    specified: function (id) {
+                        id = makeModuleMap(id, relMap, false, true).id;
+                        return hasProp(defined, id) || hasProp(registry, id);
+                    }
+                });
+
+                //Only allow undef on top level require calls
+                if (!relMap) {
+                    localRequire.undef = function (id) {
+                        //Bind any waiting define() calls to this context,
+                        //fix for #408
+                        takeGlobalQueue();
+
+                        var map = makeModuleMap(id, relMap, true),
+                            mod = getOwn(registry, id);
+
+                        removeScript(id);
+
+                        delete defined[id];
+                        delete urlFetched[map.url];
+                        delete undefEvents[id];
+
+                        //Clean queued defines too. Go backwards
+                        //in array so that the splices do not
+                        //mess up the iteration.
+                        eachReverse(defQueue, function(args, i) {
+                            if(args[0] === id) {
+                                defQueue.splice(i, 1);
+                            }
+                        });
+
+                        if (mod) {
+                            //Hold on to listeners in case the
+                            //module will be attempted to be reloaded
+                            //using a different config.
+                            if (mod.events.defined) {
+                                undefEvents[id] = mod.events;
+                            }
+
+                            cleanRegistry(id);
+                        }
+                    };
+                }
+
+                return localRequire;
+            },
+
+            /**
+             * Called to enable a module if it is still in the registry
+             * awaiting enablement. A second arg, parent, the parent module,
+             * is passed in for context, when this method is overridden by
+             * the optimizer. Not shown here to keep code compact.
+             */
+            enable: function (depMap) {
+                var mod = getOwn(registry, depMap.id);
+                if (mod) {
+                    getModule(depMap).enable();
+                }
+            },
+
+            /**
+             * Internal method used by environment adapters to complete a load event.
+             * A load event could be a script load or just a load pass from a synchronous
+             * load call.
+             * @param {String} moduleName the name of the module to potentially complete.
+             */
+            completeLoad: function (moduleName) {
+                var found, args, mod,
+                    shim = getOwn(config.shim, moduleName) || {},
+                    shExports = shim.exports;
+
+                takeGlobalQueue();
+
+                while (defQueue.length) {
+                    args = defQueue.shift();
+                    if (args[0] === null) {
+                        args[0] = moduleName;
+                        //If already found an anonymous module and bound it
+                        //to this name, then this is some other anon module
+                        //waiting for its completeLoad to fire.
+                        if (found) {
+                            break;
+                        }
+                        found = true;
+                    } else if (args[0] === moduleName) {
+                        //Found matching define call for this script!
+                        found = true;
+                    }
+
+                    callGetModule(args);
+                }
+
+                //Do this after the cycle of callGetModule in case the result
+                //of those calls/init calls changes the registry.
+                mod = getOwn(registry, moduleName);
+
+                if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
+                    if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
+                        if (hasPathFallback(moduleName)) {
+                            return;
+                        } else {
+                            return onError(makeError('nodefine',
+                                             'No define call for ' + moduleName,
+                                             null,
+                                             [moduleName]));
+                        }
+                    } else {
+                        //A script that does not call define(), so just simulate
+                        //the call for it.
+                        callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
+                    }
+                }
+
+                checkLoaded();
+            },
+
+            /**
+             * Converts a module name to a file path. Supports cases where
+             * moduleName may actually be just an URL.
+             * Note that it **does not** call normalize on the moduleName,
+             * it is assumed to have already been normalized. This is an
+             * internal API, not a public one. Use toUrl for the public API.
+             */
+            nameToUrl: function (moduleName, ext, skipExt) {
+                var paths, syms, i, parentModule, url,
+                    parentPath, bundleId,
+                    pkgMain = getOwn(config.pkgs, moduleName);
+
+                if (pkgMain) {
+                    moduleName = pkgMain;
+                }
+
+                bundleId = getOwn(bundlesMap, moduleName);
+
+                if (bundleId) {
+                    return context.nameToUrl(bundleId, ext, skipExt);
+                }
+
+                //If a colon is in the URL, it indicates a protocol is used and it is just
+                //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
+                //or ends with .js, then assume the user meant to use an url and not a module id.
+                //The slash is important for protocol-less URLs as well as full paths.
+                if (req.jsExtRegExp.test(moduleName)) {
+                    //Just a plain path, not module name lookup, so just return it.
+                    //Add extension if it is included. This is a bit wonky, only non-.js things pass
+                    //an extension, this method probably needs to be reworked.
+                    url = moduleName + (ext || '');
+                } else {
+                    //A module that needs to be converted to a path.
+                    paths = config.paths;
+
+                    syms = moduleName.split('/');
+                    //For each module name segment, see if there is a path
+                    //registered for it. Start with most specific name
+                    //and work up from it.
+                    for (i = syms.length; i > 0; i -= 1) {
+                        parentModule = syms.slice(0, i).join('/');
+
+                        parentPath = getOwn(paths, parentModule);
+                        if (parentPath) {
+                            //If an array, it means there are a few choices,
+                            //Choose the one that is desired
+                            if (isArray(parentPath)) {
+                                parentPath = parentPath[0];
+                            }
+                            syms.splice(0, i, parentPath);
+                            break;
+                        }
+                    }
+
+                    //Join the path parts together, then figure out if baseUrl is needed.
+                    url = syms.join('/');
+                    url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js'));
+                    url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
+                }
+
+                return config.urlArgs ? url +
+                                        ((url.indexOf('?') === -1 ? '?' : '&') +
+                                         config.urlArgs) : url;
+            },
+
+            //Delegates to req.load. Broken out as a separate function to
+            //allow overriding in the optimizer.
+            load: function (id, url) {
+                req.load(context, id, url);
+            },
+
+            /**
+             * Executes a module callback function. Broken out as a separate function
+             * solely to allow the build system to sequence the files in the built
+             * layer in the right sequence.
+             *
+             * @private
+             */
+            execCb: function (name, callback, args, exports) {
+                return callback.apply(exports, args);
+            },
+
+            /**
+             * callback for script loads, used to check status of loading.
+             *
+             * @param {Event} evt the event from the browser for the script
+             * that was loaded.
+             */
+            onScriptLoad: function (evt) {
+                //Using currentTarget instead of target for Firefox 2.0's sake. Not
+                //all old browsers will be supported, but this one was easy enough
+                //to support and still makes sense.
+                if (evt.type === 'load' ||
+                        (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
+                    //Reset interactive script so a script node is not held onto for
+                    //to long.
+                    interactiveScript = null;
+
+                    //Pull out the name of the module and the context.
+                    var data = getScriptData(evt);
+                    context.completeLoad(data.id);
+                }
+            },
+
+            /**
+             * Callback for script errors.
+             */
+            onScriptError: function (evt) {
+                var data = getScriptData(evt);
+                if (!hasPathFallback(data.id)) {
+                    return onError(makeError('scripterror', 'Script error for: ' + data.id, evt, [data.id]));
+                }
+            }
+        };
+
+        context.require = context.makeRequire();
+        return context;
+    }
+
+    /**
+     * Main entry point.
+     *
+     * If the only argument to require is a string, then the module that
+     * is represented by that string is fetched for the appropriate context.
+     *
+     * If the first argument is an array, then it will be treated as an array
+     * of dependency string names to fetch. An optional function callback can
+     * be specified to execute when all of those dependencies are available.
+     *
+     * Make a local req variable to help Caja compliance (it assumes things
+     * on a require that are not standardized), and to give a short
+     * name for minification/local scope use.
+     */
+    req = requirejs = function (deps, callback, errback, optional) {
+
+        //Find the right context, use default
+        var context, config,
+            contextName = defContextName;
+
+        // Determine if have config object in the call.
+        if (!isArray(deps) && typeof deps !== 'string') {
+            // deps is a config object
+            config = deps;
+            if (isArray(callback)) {
+                // Adjust args if there are dependencies
+                deps = callback;
+                callback = errback;
+                errback = optional;
+            } else {
+                deps = [];
+            }
+        }
+
+        if (config && config.context) {
+            contextName = config.context;
+        }
+
+        context = getOwn(contexts, contextName);
+        if (!context) {
+            context = contexts[contextName] = req.s.newContext(contextName);
+        }
+
+        if (config) {
+            context.configure(config);
+        }
+
+        return context.require(deps, callback, errback);
+    };
+
+    /**
+     * Support require.config() to make it easier to cooperate with other
+     * AMD loaders on globally agreed names.
+     */
+    req.config = function (config) {
+        return req(config);
+    };
+
+    /**
+     * Execute something after the current tick
+     * of the event loop. Override for other envs
+     * that have a better solution than setTimeout.
+     * @param  {Function} fn function to execute later.
+     */
+    req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
+        setTimeout(fn, 4);
+    } : function (fn) { fn(); };
+
+    /**
+     * Export require as a global, but only if it does not already exist.
+     */
+    if (!require) {
+        require = req;
+    }
+
+    req.version = version;
+
+    //Used to filter out dependencies that are already paths.
+    req.jsExtRegExp = /^\/|:|\?|\.js$/;
+    req.isBrowser = isBrowser;
+    s = req.s = {
+        contexts: contexts,
+        newContext: newContext
+    };
+
+    //Create default context.
+    req({});
+
+    //Exports some context-sensitive methods on global require.
+    each([
+        'toUrl',
+        'undef',
+        'defined',
+        'specified'
+    ], function (prop) {
+        //Reference from contexts instead of early binding to default context,
+        //so that during builds, the latest instance of the default context
+        //with its config gets used.
+        req[prop] = function () {
+            var ctx = contexts[defContextName];
+            return ctx.require[prop].apply(ctx, arguments);
+        };
+    });
+
+    if (isBrowser) {
+        head = s.head = document.getElementsByTagName('head')[0];
+        //If BASE tag is in play, using appendChild is a problem for IE6.
+        //When that browser dies, this can be removed. Details in this jQuery bug:
+        //http://dev.jquery.com/ticket/2709
+        baseElement = document.getElementsByTagName('base')[0];
+        if (baseElement) {
+            head = s.head = baseElement.parentNode;
+        }
+    }
+
+    /**
+     * Any errors that require explicitly generates will be passed to this
+     * function. Intercept/override it if you want custom error handling.
+     * @param {Error} err the error object.
+     */
+    req.onError = defaultOnError;
+
+    /**
+     * Creates the node for the load command. Only used in browser envs.
+     */
+    req.createNode = function (config, moduleName, url) {
+        var node = config.xhtml ?
+                document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
+                document.createElement('script');
+        node.type = config.scriptType || 'text/javascript';
+        node.charset = 'utf-8';
+        node.async = true;
+        return node;
+    };
+
+    /**
+     * Does the request to load a module for the browser case.
+     * Make this a separate function to allow other environments
+     * to override it.
+     *
+     * @param {Object} context the require context to find state.
+     * @param {String} moduleName the name of the module.
+     * @param {Object} url the URL to the module.
+     */
+    req.load = function (context, moduleName, url) {
+        var config = (context && context.config) || {},
+            node;
+        if (isBrowser) {
+            //In the browser so use a script tag
+            node = req.createNode(config, moduleName, url);
+
+            node.setAttribute('data-requirecontext', context.contextName);
+            node.setAttribute('data-requiremodule', moduleName);
+
+            //Set up load listener. Test attachEvent first because IE9 has
+            //a subtle issue in its addEventListener and script onload firings
+            //that do not match the behavior of all other browsers with
+            //addEventListener support, which fire the onload event for a
+            //script right after the script execution. See:
+            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
+            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
+            //script execution mode.
+            if (node.attachEvent &&
+                    //Check if node.attachEvent is artificially added by custom script or
+                    //natively supported by browser
+                    //read https://github.com/jrburke/requirejs/issues/187
+                    //if we can NOT find [native code] then it must NOT natively supported.
+                    //in IE8, node.attachEvent does not have toString()
+                    //Note the test for "[native code" with no closing brace, see:
+                    //https://github.com/jrburke/requirejs/issues/273
+                    !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
+                    !isOpera) {
+                //Probably IE. IE (at least 6-8) do not fire
+                //script onload right after executing the script, so
+                //we cannot tie the anonymous define call to a name.
+                //However, IE reports the script as being in 'interactive'
+                //readyState at the time of the define call.
+                useInteractive = true;
+
+                node.attachEvent('onreadystatechange', context.onScriptLoad);
+                //It would be great to add an error handler here to catch
+                //404s in IE9+. However, onreadystatechange will fire before
+                //the error handler, so that does not help. If addEventListener
+                //is used, then IE will fire error before load, but we cannot
+                //use that pathway given the connect.microsoft.com issue
+                //mentioned above about not doing the 'script execute,
+                //then fire the script load event listener before execute
+                //next script' that other browsers do.
+                //Best hope: IE10 fixes the issues,
+                //and then destroys all installs of IE 6-9.
+                //node.attachEvent('onerror', context.onScriptError);
+            } else {
+                node.addEventListener('load', context.onScriptLoad, false);
+                node.addEventListener('error', context.onScriptError, false);
+            }
+            node.src = url;
+
+            //For some cache cases in IE 6-8, the script executes before the end
+            //of the appendChild execution, so to tie an anonymous define
+            //call to the module name (which is stored on the node), hold on
+            //to a reference to this node, but clear after the DOM insertion.
+            currentlyAddingScript = node;
+            if (baseElement) {
+                head.insertBefore(node, baseElement);
+            } else {
+                head.appendChild(node);
+            }
+            currentlyAddingScript = null;
+
+            return node;
+        } else if (isWebWorker) {
+            try {
+                //In a web worker, use importScripts. This is not a very
+                //efficient use of importScripts, importScripts will block until
+                //its script is downloaded and evaluated. However, if web workers
+                //are in play, the expectation that a build has been done so that
+                //only one script needs to be loaded anyway. This may need to be
+                //reevaluated if other use cases become common.
+                importScripts(url);
+
+                //Account for anonymous modules
+                context.completeLoad(moduleName);
+            } catch (e) {
+                context.onError(makeError('importscripts',
+                                'importScripts failed for ' +
+                                    moduleName + ' at ' + url,
+                                e,
+                                [moduleName]));
+            }
+        }
+    };
+
+    function getInteractiveScript() {
+        if (interactiveScript && interactiveScript.readyState === 'interactive') {
+            return interactiveScript;
+        }
+
+        eachReverse(scripts(), function (script) {
+            if (script.readyState === 'interactive') {
+                return (interactiveScript = script);
+            }
+        });
+        return interactiveScript;
+    }
+
+    //Look for a data-main script attribute, which could also adjust the baseUrl.
+    if (isBrowser && !cfg.skipDataMain) {
+        //Figure out baseUrl. Get it from the script tag with require.js in it.
+        eachReverse(scripts(), function (script) {
+            //Set the 'head' where we can append children by
+            //using the script's parent.
+            if (!head) {
+                head = script.parentNode;
+            }
+
+            //Look for a data-main attribute to set main script for the page
+            //to load. If it is there, the path to data main becomes the
+            //baseUrl, if it is not already set.
+            dataMain = script.getAttribute('data-main');
+            if (dataMain) {
+                //Preserve dataMain in case it is a path (i.e. contains '?')
+                mainScript = dataMain;
+
+                //Set final baseUrl if there is not already an explicit one.
+                if (!cfg.baseUrl) {
+                    //Pull off the directory of data-main for use as the
+                    //baseUrl.
+                    src = mainScript.split('/');
+                    mainScript = src.pop();
+                    subPath = src.length ? src.join('/')  + '/' : './';
+
+                    cfg.baseUrl = subPath;
+                }
+
+                //Strip off any trailing .js since mainScript is now
+                //like a module name.
+                mainScript = mainScript.replace(jsSuffixRegExp, '');
+
+                 //If mainScript is still a path, fall back to dataMain
+                if (req.jsExtRegExp.test(mainScript)) {
+                    mainScript = dataMain;
+                }
+
+                //Put the data-main script in the files to load.
+                cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
+
+                return true;
+            }
+        });
+    }
+
+    /**
+     * The function that handles definitions of modules. Differs from
+     * require() in that a string for the module should be the first argument,
+     * and the function to execute after dependencies are loaded should
+     * return a value to define the module corresponding to the first argument's
+     * name.
+     */
+    define = function (name, deps, callback) {
+        var node, context;
+
+        //Allow for anonymous modules
+        if (typeof name !== 'string') {
+            //Adjust args appropriately
+            callback = deps;
+            deps = name;
+            name = null;
+        }
+
+        //This module may not have dependencies
+        if (!isArray(deps)) {
+            callback = deps;
+            deps = null;
+        }
+
+        //If no name, and callback is a function, then figure out if it a
+        //CommonJS thing with dependencies.
+        if (!deps && isFunction(callback)) {
+            deps = [];
+            //Remove comments from the callback string,
+            //look for require calls, and pull them into the dependencies,
+            //but only if there are function args.
+            if (callback.length) {
+                callback
+                    .toString()
+                    .replace(commentRegExp, '')
+                    .replace(cjsRequireRegExp, function (match, dep) {
+                        deps.push(dep);
+                    });
+
+                //May be a CommonJS thing even without require calls, but still
+                //could use exports, and module. Avoid doing exports and module
+                //work though if it just needs require.
+                //REQUIRES the function to expect the CommonJS variables in the
+                //order listed below.
+                deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
+            }
+        }
+
+        //If in IE 6-8 and hit an anonymous define() call, do the interactive
+        //work.
+        if (useInteractive) {
+            node = currentlyAddingScript || getInteractiveScript();
+            if (node) {
+                if (!name) {
+                    name = node.getAttribute('data-requiremodule');
+                }
+                context = contexts[node.getAttribute('data-requirecontext')];
+            }
+        }
+
+        //Always save off evaluating the def call until the script onload handler.
+        //This allows multiple modules to be in a file without prematurely
+        //tracing dependencies, and allows for anonymous module support,
+        //where the module name is not known until the script onload event
+        //occurs. If no context, use the global queue, and get it processed
+        //in the onscript load callback.
+        (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
+    };
+
+    define.amd = {
+        jQuery: true
+    };
+
+
+    /**
+     * Executes the text. Normally just uses eval, but can be modified
+     * to use a better, environment-specific call. Only used for transpiling
+     * loader plugins, not for plain JS modules.
+     * @param {String} text the text to execute/evaluate.
+     */
+    req.exec = function (text) {
+        /*jslint evil: true */
+        return eval(text);
+    };
+
+    //Set up with config info.
+    req(cfg);
+}(this));
diff --git a/webcore/test/TC/test-lazy-w-react.html b/webcore/test/TC/test-lazy-w-react.html
new file mode 100644
index 0000000..b8475b7
--- /dev/null
+++ b/webcore/test/TC/test-lazy-w-react.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dicoogle web plugin test chamber</title>
+    
+    <script src='./document-register-element.js'></script>
+    <script src='./require.js'></script>
+    <script src="./react-0.13.0.js"></script>
+    <script src='../../dist/dicoogle-webcore.js'></script>
+    <script>
+    function onReveal() {
+      var slotdiv = document.getElementById("slotdiv");
+      slotdiv.innerHTML = '';
+      var dicoogleSlot = document.createElement("dicoogle-slot");
+      dicoogleSlot.setAttribute('data-slot-id', 'fordummy');
+      slotdiv.appendChild(dicoogleSlot);
+    }
+    </script>
+    <style>
+      div.slotdiv {
+        margin-right: auto;
+        width: 20cm;
+        border-style: ridge;
+        border-width: 4px;
+        border-color: #4499CC;
+        padding: 8px;
+      }
+      .dicoogle-webcore-fordummy_0 {
+        display: inline-block;
+        position: relative;
+        width: 10cm;
+        margin-right: auto;
+        vertical-align: top;
+        background: #CFF;
+      }
+      .dicoogle-webcore-fordummy_1 {
+        display: inline-block;
+        position: relative;
+        width: 10cm;
+        margin-left: auto;
+        vertical-align: top;
+        background: #FFC;
+      }
+    </style>
+  </head>
+  <body>
+    <h2>Test Chamber</h2>
+    <p>This page will create a Dicoogle Web UI slot with the slot id <tt>fordummy</tt> as soon as the button below is pressed. React was included.
+    If you are hosting this web page directly through the Dicoogle server, then any plugin for this slot will be loaded
+    automatically. Otherwise, try setting the server's base URL (in the code) and allow CORS on your browser.</p>
+    
+    <div id="slotdiv" class="slotdiv">
+      <input type="button" id="btnReveal" value="Open Dicoogle Slot" onclick="onReveal()"></input>
+    </div>
+    
+    <script>
+      require(['dicoogle-webcore','react'], function(DicoogleWeb) {
+        DicoogleWeb.init('http://localhost:8080/');
+      });
+    </script>
+  </body>
+</html>
diff --git a/webcore/test/TC/test-query-result-w-react.html b/webcore/test/TC/test-query-result-w-react.html
new file mode 100644
index 0000000..4b5f792
--- /dev/null
+++ b/webcore/test/TC/test-query-result-w-react.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dicoogle web plugin test chamber (Query + Result)</title>
+    <script src='./document-register-element.js'></script>
+    <script src='./require.js'></script>
+    <script src='./react-0.13.0.js'></script>
+<!--    <script src='./reactable.js'></script> -->
+<!--    <script src='./react-dropzone.js'></script> -->
+    <script src='../../dist/dicoogle-webcore.js'></script>
+    <style>
+    td, th {
+      border: 1px solid #888;
+      padding: 0.4rem;
+    }
+    .reactable-page-button {
+      border: 1px solid #888;
+      padding: 0.15rem;
+      margin: 0.2rem;
+      cursor: pointer; cursor: hand;
+    }
+    .reactable-current-page {
+      background-color: #CCC;
+    }
+    </style>
+  </head>
+  <body>
+    <h2>Test Chamber (Query + Result)</h2>
+    This page holds two Dicoogle Web UI slots! One with the id <tt>query</tt> and another with the id <tt>result</tt>.
+    It is excellent for experimenting with Dicoogle search operations. This page also includes React (<tt>'react'</tt>).
+    
+    <dicoogle-slot data-slot-id='query' ></dicoogle-slot>
+    <hr>
+    <dicoogle-slot data-slot-id='result' ></dicoogle-slot>
+    
+    <script>
+      require(['dicoogle-webcore','react','reactable'], function(DicoogleWebcore, React, Reactable) {
+        DicoogleWebcore.init('http://localhost:8080/');
+      });
+    </script>
+  </body>
+</html>
diff --git a/webcore/test/TC/test-w-react.html b/webcore/test/TC/test-w-react.html
new file mode 100644
index 0000000..01061a9
--- /dev/null
+++ b/webcore/test/TC/test-w-react.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dicoogle web plugin test chamber (with React)</title>
+    <script src='./document-register-element.js'></script>
+    <script src='./require.js'></script>
+    <script src="./react-0.13.0.js"></script>
+    <script src='../../dist/dicoogle-webcore.js'></script>
+    <style>
+      div.slotdiv {
+        margin-right: auto;
+        max-width: 16cm;
+        width: 100%;
+        border-styl: ridge;
+        border-width: 4px;
+        border-color: #4499CC;
+        padding: 8px;
+      }
+    </style>
+  </head>
+  <body>
+    <h2>Test Chamber (with React)</h2>
+    <p>This page holds a Dicoogle Web UI slot with the id <tt>fordummy</tt>.
+    If you are hosting this web page directly through the Dicoogle server, then any plugin for this slot will be loaded
+    automatically. Otherwise, try setting the server's base URL (in the code) and allow CORS on your browser.</p>
+    <p>
+      This page already contains React, which means plugins do not have to embed it. They can just <tt>require</tt> it.
+    </p>
+    
+    <div class="slotdiv">
+      <dicoogle-slot data-slot-id='fordummy'></dicoogle-slot>
+    </div>
+    
+    <script>
+      require(['dicoogle-webcore','react'], function(DicoogleWeb, React) {
+        DicoogleWeb.init('http://localhost:8080/');
+      });
+    </script>
+  </body>
+</html>
diff --git a/webcore/test/TC/test.html b/webcore/test/TC/test.html
new file mode 100644
index 0000000..f4db9e3
--- /dev/null
+++ b/webcore/test/TC/test.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Dicoogle web plugin test chamber</title>
+    
+    <script src='./document-register-element.js'></script>
+    <script src='./require.js'></script>
+    <script src='../../dist/dicoogle-webcore.js'></script>
+    <style>
+      div.slotdiv {
+        margin-right: auto;
+        max-width: 16cm;
+        width: 100%;
+        border-style: ridge;
+        border-width: 4px;
+        border-color: #4499CC;
+        padding: 8px;
+      }
+    </style>
+  </head>
+  <body>
+    <h2>Test Chamber</h2>
+    <p>This page holds a Dicoogle Web UI slot with the slot id <tt>fordummy</tt>.
+    If you are hosting this web page directly through the Dicoogle server, then any plugin for this slot will be loaded
+    automatically. Otherwise, try setting the server's base URL (in the code) and allow CORS on your browser.</p>
+    
+    <div class="slotdiv">
+      <dicoogle-slot data-slot-id='fordummy'></dicoogle-slot>
+    </div>
+    
+    <script>
+      require(['dicoogle-webcore'], function(DicoogleWeb) {
+        DicoogleWeb.init('http://localhost:8080/');
+      });
+    </script>
+  </body>
+</html>
diff --git a/webcore/test/dummy/dummy.js b/webcore/test/dummy/dummy.js
new file mode 100644
index 0000000..63fea60
--- /dev/null
+++ b/webcore/test/dummy/dummy.js
@@ -0,0 +1,66 @@
+/* dummy.js - Dummy module file
+ */
+console.log("Hello, I'm dummy!");
+
+module.exports = function DummyModule() {
+  // derp
+  var index = null;
+  var providers = [];
+  var exhibit = document.createElement('b');
+  exhibit.style['font-size'] = '16px';
+  exhibit.style['font-family'] = 'Courier New';
+  var interv = null;
+  var button = document.createElement('input');
+   
+  function onClick() {
+     if (!interv) {
+       Dicoogle.getQueryProviders(function(error, result) {
+         if (error) {
+           console.error('An error occurred: ', error);
+           return;
+         }
+         providers = result;
+         index = 0;
+         exhibit.innerHTML = providers[0];
+         interv = setInterval(function(){
+           index = (index+1)%providers.length;
+           exhibit.innerHTML = providers[index];
+         }, 1000);
+         button.value = 'Stop!';
+       });
+     } else {
+       clearInterval(interv);
+       exhibit.innerHTML = '';
+       interv = null;
+       index = null;
+       button.value = 'Click me!';
+     }
+  }
+   
+  button.type = 'button';
+  button.value = 'Click me!';
+  button.onclick = onClick;
+  
+  this.render = function(parent) {
+     var d = document.createElement('div');
+     d.innerHTML = '<h3>DUMMY Module</h3>';
+     d.innerHTML +=
+         '<p>This is a test Dicoogle web UI module to let developers understand how to'
+       + ' develop Dicoogle Web UI\'s.<br>\n'
+       + 'Since it\'s best to show something useful and interactive,'
+       + ' try pushing the button below. It will request all query providers and sequentially'
+       + ' cycle between their names. This is as rudimentary as it can get, but modules are'
+       + ' free to use the vast range of web components to make them more interesting.</p>';
+     
+     d.appendChild(button);
+     var labelProviders = document.createElement('span');
+     labelProviders.style['font-size'] = '16px';
+     labelProviders.style.display = 'block-inline';
+     labelProviders.innerHTML = 'Query Providers: ';
+     d.appendChild(document.createElement('br'));
+     d.appendChild(labelProviders);
+     d.appendChild(exhibit);
+     parent.appendChild(d);
+   };
+};
+ 
diff --git a/webcore/test/dummy/package.json b/webcore/test/dummy/package.json
new file mode 100644
index 0000000..5d1ba1e
--- /dev/null
+++ b/webcore/test/dummy/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "dummy",
+  "version": "0.1.0",
+  "description": "Dummy Web UI plugin",
+  "scripts": {
+    "build": "uglifyjs dummy.js --compress keep_fargs=true --mangle -r require,module,exports -o module.js",
+    "build-debug": "uglifyjs dummy.js --source-map module.js.map -b -o module.js",
+    "prepublish": "npm run build"
+  },
+  "dicoogle": {
+    "slot-id": "menu",
+    "caption": "Dummy",
+    "module-file": "module.js"
+  },
+  "devDependencies": {
+    "uglifyjs": "^2.4.10"
+  }
+}
diff --git a/webcore/test/react-todo/.babelrc b/webcore/test/react-todo/.babelrc
new file mode 100644
index 0000000..86c445f
--- /dev/null
+++ b/webcore/test/react-todo/.babelrc
@@ -0,0 +1,3 @@
+{
+  "presets": ["es2015", "react"]
+}
diff --git a/webcore/test/react-todo/module.js b/webcore/test/react-todo/module.js
new file mode 100644
index 0000000..d4215bc
--- /dev/null
+++ b/webcore/test/react-todo/module.js
@@ -0,0 +1,89 @@
+'use strict';
+
+var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps [...]
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             [...]
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+
+var _react = require('react');
+
+var _react2 = _interopRequireDefault(_react);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var TodoItems = _react2.default.createClass({
+  render: function render() {
+    var createItem = function createItem(itemText, i) {
+      return _react2.default.createElement(
+        'li',
+        { key: i },
+        itemText
+      );
+    };
+    return _react2.default.createElement(
+      'ul',
+      null,
+      this.props.items.map(createItem)
+    );
+  }
+});
+
+var TodoApp = _react2.default.createClass({
+  getInitialState: function getInitialState() {
+    return { items: [], text: '' };
+  },
+  onChange: function onChange(e) {
+    this.setState({ text: e.target.value });
+  },
+  handleSubmit: function handleSubmit(e) {
+    e.preventDefault();
+    var nextItems = this.state.items.concat([this.state.text]);
+    var nextText = '';
+    this.setState({ items: nextItems, text: nextText });
+  },
+  render: function render() {
+    return _react2.default.createElement(
+      'div',
+      null,
+      _react2.default.createElement(
+        'h3',
+        null,
+        'TODO List:'
+      ),
+      _react2.default.createElement(TodoItems, { items: this.state.items }),
+      _react2.default.createElement(
+        'form',
+        { onSubmit: this.handleSubmit },
+        _react2.default.createElement('input', { onChange: this.onChange, value: this.state.text }),
+        _react2.default.createElement(
+          'button',
+          null,
+          'Add #' + (this.state.items.length + 1)
+        )
+      )
+    );
+  }
+});
+
+var Todo = (function () {
+  function Todo() {
+    _classCallCheck(this, Todo);
+  }
+
+  _createClass(Todo, [{
+    key: 'render',
+    value: function render(parent) {
+      //React.render(this.r, parent);
+      return _react2.default.createElement(TodoApp, null);
+    }
+  }]);
+
+  return Todo;
+})();
+
+exports.default = Todo;
+
diff --git a/webcore/test/react-todo/package.json b/webcore/test/react-todo/package.json
new file mode 100644
index 0000000..449da3d
--- /dev/null
+++ b/webcore/test/react-todo/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "react-todo",
+  "version": "0.1.0",
+  "private": true,
+  "description": "A TODO list for Dicoogle",
+  "scripts": {
+    "build": "babel todo.jsx > module.js",
+    "prepublish": "npm run build"
+  },
+  "dicoogle": {
+    "caption": "TODO list",
+    "slot-id": "menu",
+    "module-file": "module.js"
+  },
+  "devDependencies": {
+    "babel-cli": "^6.1.2",
+    "babel-preset-es2015": "^6.1.2",
+    "babel-preset-react": "^6.1.2"
+  }
+}
diff --git a/webcore/test/react-todo/todo.jsx b/webcore/test/react-todo/todo.jsx
new file mode 100644
index 0000000..4eb9b30
--- /dev/null
+++ b/webcore/test/react-todo/todo.jsx
@@ -0,0 +1,47 @@
+/* todo.jsx - To-do list for Dicoogle
+ */
+import React from 'react';
+
+const TodoItems = React.createClass({
+  render() {
+    const createItem = (itemText, i) => {
+      return <li key={i}>{itemText}</li>;
+    };
+    return <ul>{this.props.items.map(createItem)}</ul>;
+  }
+});
+
+const TodoApp = React.createClass({
+  getInitialState() {
+    return {items: [], text: ''};
+  },
+  onChange(e) {
+    this.setState({text: e.target.value});
+  },
+  handleSubmit(e) {
+    e.preventDefault();
+    let nextItems = this.state.items.concat([this.state.text]);
+    let nextText = '';
+    this.setState({items: nextItems, text: nextText});
+  },
+  render() {
+    return (
+      <div>
+        <h3>TODO List:</h3>
+        <TodoItems items={this.state.items} />
+        <form onSubmit={this.handleSubmit}>
+          <input onChange={this.onChange} value={this.state.text} />
+          <button>{'Add #' + (this.state.items.length + 1)}</button>
+        </form>
+      </div>
+    );
+  }
+});
+
+export default class Todo {
+
+  render(parent) {
+    //React.render(this.r, parent);
+    return <TodoApp />;
+  }
+}
diff --git a/webcore/test/simple-query/module.js b/webcore/test/simple-query/module.js
new file mode 100644
index 0000000..639f605
--- /dev/null
+++ b/webcore/test/simple-query/module.js
@@ -0,0 +1,50 @@
+/* simple-query.js - Simple query module
+ */
+  
+module.exports = function() {
+  var input = document.createElement('input');
+  var button = document.createElement('input');
+  var chkKeyword = document.createElement('input'); 
+  var lblKeyword = document.createElement('label');
+
+  function onClick() { 
+    var query = input.value;
+    DicoogleWeb.issueQuery(query, {
+      keyword: chkKeyword.checked,
+      provider: ['lucene']
+    }, function(error, result) {
+      if (error) {
+        console.error('An error occurred: ', error);
+        return;
+      }
+      console.log('Complete.');
+    });
+  }
+   
+  input.type = 'text';
+  input.placeholder = 'Search query...';
+  input.onkeypress = function searchKeyPress(event) {
+    if (event.keyCode == 13) {
+      onClick();
+    }
+  };
+  
+  chkKeyword.type = 'checkbox';
+  chkKeyword.value = 'keyword';
+  chkKeyword.checked = true;
+
+  lblKeyword.appendChild(chkKeyword);
+  lblKeyword.appendChild(document.createTextNode("keyword"));
+ 
+  button.type = 'button';
+  button.value = 'Search';
+  button.onclick = onClick;
+  
+  this.render = function(parent) {
+     var d = document.createElement('div');
+     d.appendChild(input);
+     d.appendChild(lblKeyword);
+     d.appendChild(button);
+     parent.appendChild(d);
+   };
+};
diff --git a/webcore/test/simple-query/package.json b/webcore/test/simple-query/package.json
new file mode 100644
index 0000000..5a60c4b
--- /dev/null
+++ b/webcore/test/simple-query/package.json
@@ -0,0 +1,13 @@
+{
+  "name": "simple-query",
+  "version": "0.0.1",
+  "description": "Simple Query Web UI plugin",
+  "scripts": {
+    "build": "cp simple-query.js module.js"
+  },
+  "dicoogle": {
+    "caption": "Simple Query",
+    "slot-id": "query",
+    "module-file": "module.js"
+  }
+}
diff --git a/webcore/test/simple-query/simple-query.js b/webcore/test/simple-query/simple-query.js
new file mode 100644
index 0000000..639f605
--- /dev/null
+++ b/webcore/test/simple-query/simple-query.js
@@ -0,0 +1,50 @@
+/* simple-query.js - Simple query module
+ */
+  
+module.exports = function() {
+  var input = document.createElement('input');
+  var button = document.createElement('input');
+  var chkKeyword = document.createElement('input'); 
+  var lblKeyword = document.createElement('label');
+
+  function onClick() { 
+    var query = input.value;
+    DicoogleWeb.issueQuery(query, {
+      keyword: chkKeyword.checked,
+      provider: ['lucene']
+    }, function(error, result) {
+      if (error) {
+        console.error('An error occurred: ', error);
+        return;
+      }
+      console.log('Complete.');
+    });
+  }
+   
+  input.type = 'text';
+  input.placeholder = 'Search query...';
+  input.onkeypress = function searchKeyPress(event) {
+    if (event.keyCode == 13) {
+      onClick();
+    }
+  };
+  
+  chkKeyword.type = 'checkbox';
+  chkKeyword.value = 'keyword';
+  chkKeyword.checked = true;
+
+  lblKeyword.appendChild(chkKeyword);
+  lblKeyword.appendChild(document.createTextNode("keyword"));
+ 
+  button.type = 'button';
+  button.value = 'Search';
+  button.onclick = onClick;
+  
+  this.render = function(parent) {
+     var d = document.createElement('div');
+     d.appendChild(input);
+     d.appendChild(lblKeyword);
+     d.appendChild(button);
+     parent.appendChild(d);
+   };
+};
diff --git a/webcore/test/simple-result/Gruntfile.js b/webcore/test/simple-result/Gruntfile.js
new file mode 100644
index 0000000..42fff8c
--- /dev/null
+++ b/webcore/test/simple-result/Gruntfile.js
@@ -0,0 +1,96 @@
+module.exports = function(grunt) {
+
+  var amdDependencies = ['dicoogle-webcore', 'react', 'reactable'];
+
+  // Project configuration.
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+    react: {
+      all: {
+        src: '<%= pkg.name %>.jsx',
+        dest: 'build/<%= pkg.name %>.js'
+      }
+    },
+    jshint: {
+      all: ['Gruntfile.js', 'build/<%= pkg.name %>.js'],
+      options: {
+      }
+    },
+    browserify: {
+      all: {
+        src: 'build/<%= pkg.name %>.js',
+        dest: 'build/module.js',
+        options: {
+          browserifyOptions: {
+            standalone: '<%= pkg.name %>'
+          },
+          external: ['react']
+        }
+      }
+    },
+//    umd: {
+//      all: {
+//        options: {
+//          src: 'build/<%= pkg.name %>.js',
+//          dest: 'build/module.js',
+//          deps: {
+//            amd: amdDependencies
+//          },
+//          template: 'template/returnModuleExports.hbs'
+//          template: 'template/unit.hbs'
+//        },
+//      }
+//    }, 
+    uglify: {
+      options: {
+        //banner: '<%= grunt.file.read("license-header.txt") %>'
+      },
+      minimize: {
+        options: {
+          compress: true,
+          preserveComments: false,
+          mangle: true
+        },
+        src: 'build/module.js',
+        dest: 'module.min.js'
+      },
+      pretty: {
+        options: {
+          beautify: true,
+          compress: false,
+          mangle: false,
+          preserveComments: true
+        },
+        src: 'build/module.js',
+        dest: 'module.js'
+      },
+      debug: {
+        options: {
+          beautify: true,
+          compress: false,
+          mangle: false,
+          preserveComments: true,
+          sourceMap: true
+        },
+        src: 'build/module.js',
+        dest: 'module.js'
+      }
+    },
+    clean: { all: ['build/'] }
+  });
+
+  // Load plugin tasks.
+  grunt.loadNpmTasks('grunt-react');
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-browserify');
+  //grunt.loadNpmTasks('grunt-contrib-concat');
+  //grunt.loadNpmTasks('grunt-umd');
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-clean');
+
+  // Default task(s).
+  grunt.registerTask('default',
+    ['react','jshint','browserify','uglify:minimize','uglify:pretty','clean']);
+  grunt.registerTask('debug',
+    ['react','jshint','browserify','uglify:debug']);
+};
diff --git a/webcore/test/simple-result/dep/reactable.js b/webcore/test/simple-result/dep/reactable.js
new file mode 100644
index 0000000..89cbd2c
--- /dev/null
+++ b/webcore/test/simple-result/dep/reactable.js
@@ -0,0 +1,955 @@
+(function (root, factory) {
+    if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module.
+        define('reactable', ['react'], factory);
+    } else if (typeof exports === 'object') {
+        // Node. Does not work with strict CommonJS, but
+        // only CommonJS-like environments that support module.exports,
+        // like Node.
+        module.exports = factory(require('react'));
+    } else {
+        // Browser globals (root is window)
+        root.Reactable = factory(root.React);
+    }
+}(this, function (React) {
+    "use strict";
+    var exports = {};
+
+    // Array.prototype.map polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill
+    // Production steps of ECMA-262, Edition 5, 15.4.4.19
+    // Reference: http://es5.github.io/#x15.4.4.19
+    if (!Array.prototype.map) {
+
+        Array.prototype.map = function(callback, thisArg) {
+            var T, A, k;
+
+            if (this === null) {
+                throw new TypeError(" this is null or not defined");
+            }
+
+            var O = Object(this);
+            var len = O.length >>> 0;
+
+            if (typeof callback !== "function") {
+                throw new TypeError(callback + " is not a function");
+            }
+
+            if (arguments.length > 1) {
+                T = thisArg;
+            }
+
+            A = new Array(len);
+            k = 0;
+
+            while (k < len) {
+                var kValue, mappedValue;
+                if (k in O) {
+                    kValue = O[k];
+                    mappedValue = callback.call(T, kValue, k, O);
+                    A[k] = mappedValue;
+                }
+                k++;
+            }
+            return A;
+        };
+    }
+
+    // Array.prototype.indexOf polyfill for IE8
+    if (!Array.prototype.indexOf) {
+        Array.prototype.indexOf = function(elt /*, from*/) {
+            var len = this.length >>> 0;
+
+            var from = Number(arguments[1]) || 0;
+            from = (from < 0) ? Math.ceil(from) : Math.floor(from);
+            if (from < 0) {
+                from += len;
+            }
+
+            for (; from < len; from++) {
+                if (from in this && this[from] === elt) {
+                    return from;
+                }
+            }
+            return -1;
+        };
+    }
+
+    // Array.prototype.find polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
+    if (!Array.prototype.find) {
+        Object.defineProperty(Array.prototype, 'find', {
+            enumerable: false,
+            configurable: true,
+            writable: true,
+            value: function(predicate) {
+                if (this === null) {
+                    throw new TypeError('Array.prototype.find called on null or undefined');
+                }
+                if (typeof predicate !== 'function') {
+                    throw new TypeError('predicate must be a function');
+                }
+                var list = Object(this);
+                var length = list.length >>> 0;
+                var thisArg = arguments[1];
+                var value;
+
+                for (var i = 0; i < length; i++) {
+                    if (i in list) {
+                        value = list[i];
+                        if (predicate.call(thisArg, value, i, list)) {
+                            return value;
+                        }
+                    }
+                }
+                return undefined;
+            }
+        });
+    }
+
+    if (!Array.isArray) {
+        Array.isArray = function (value) {
+            return Object.prototype.toString.call(value) === '[object Array]';
+        };
+    }
+
+    if (!Object.assign) {
+        Object.defineProperty(Object, "assign", {
+            enumerable: false,
+            configurable: true,
+            writable: true,
+            value: function(target, firstSource) {
+                if (target === undefined || target === null)
+                    throw new TypeError("Cannot convert first argument to object");
+                var to = Object(target);
+                for (var i = 1; i < arguments.length; i++) {
+                    var nextSource = arguments[i];
+                    if (nextSource === undefined || nextSource === null) continue;
+                    var keysArray = Object.keys(Object(nextSource));
+                    for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
+                        var nextKey = keysArray[nextIndex];
+                        var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
+                        if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey];
+                    }
+                }
+                return to;
+            }
+        });
+    }
+
+    function Unsafe(content) {
+        this.content = content;
+    }
+
+    Unsafe.prototype.toString = function() {
+        return this.content;
+    };
+
+    function stringable(thing) {
+        return thing !== null && typeof(thing) !== 'undefined' && typeof(thing.toString === 'function');
+    }
+
+    // this is a bit hacky - it'd be nice if React exposed an API for this
+    function isReactComponent(thing) {
+        return thing !== null && typeof(thing) === 'object' && typeof(thing.props) !== 'undefined';
+    }
+
+    React.Children.children = function(children) {
+        return React.Children.map(children, function(x) { return x; }) || [];
+    };
+
+    exports.unsafe = function(str) {
+        return new Unsafe(str);
+    };
+
+    exports.Sort = {
+        Numeric: function(a, b) {
+            var valA = parseFloat(a.toString().replace(',', ''));
+            var valB = parseFloat(b.toString().replace(',', ''));
+
+            // Sort non-numeric values alphabetically at the bottom of the list
+            if (isNaN(valA) && isNaN(valB)) {
+                valA = a;
+                valB = b;
+            } else {
+                if (isNaN(valA)) {
+                    return 1;
+                }
+                if (isNaN(valB)) {
+                    return -1;
+                }
+            }
+
+            if (valA < valB) {
+                return -1;
+            }
+            if (valA > valB) {
+                return 1;
+            }
+
+            return 0;
+        },
+
+        NumericInteger: function(a, b) {
+          if (isNaN(a) || isNaN(b)) {
+            return a > b ? 1 : -1;
+          }
+
+          return a - b;
+        },
+
+        Currency: function(a, b) {
+            // Parse out dollar signs, then do a regular numeric sort
+            // TODO: handle non-American currency
+
+            if (a[0] === '$') {
+                a = a.substring(1);
+            }
+            if (b[0] === '$') {
+                b = b.substring(1);
+            }
+
+            return exports.Sort.Numeric(a, b);
+        },
+
+        Date: function(a, b) {
+            // Note: this function tries to do a standard javascript string -> date conversion
+            // If you need more control over the date string format, consider using a different
+            // date library and writing your own function
+            var valA = Date.parse(a);
+            var valB = Date.parse(b);
+
+            // Handle non-date values with numeric sort
+            // Sort non-numeric values alphabetically at the bottom of the list
+            if (isNaN(valA) || isNaN(valB)) {
+                return exports.Sort.Numeric(a, b);
+            }
+
+            if (valA > valB) {
+                return 1;
+            }
+            if (valB > valA) {
+                return -1;
+            }
+
+            return 0;
+        },
+
+        CaseInsensitive: function(a, b) {
+            return a.toLowerCase().localeCompare(b.toLowerCase());
+        }
+    };
+
+    var Td = exports.Td = React.createClass({displayName: "Td",
+        handleClick: function(e){
+            if (typeof this.props.handleClick === 'function') {
+                return this.props.handleClick(e, this);
+            }
+        },
+        render: function() {
+            var tdProps = {
+                className: this.props.className,
+                onClick: this.handleClick
+            };
+
+            // Attach any properties on the column to this Td object to allow things like custom event handlers
+            if (typeof(this.props.column) === 'object') {
+                for (var key in this.props.column) {
+                    if (key !== 'key' && key !== 'name') {
+                        tdProps[key] = this.props.column[key];
+                    }
+                }
+            }
+
+            var data = this.props.data;
+
+            if (typeof(this.props.children) !== 'undefined') {
+                if (isReactComponent(this.props.children)) {
+                    data = this.props.children;
+                } else if (
+                    typeof(this.props.data) === 'undefined' &&
+                        stringable(this.props.children)
+                ) {
+                    data = this.props.children.toString();
+                }
+
+                if (this.props.children instanceof Unsafe) {
+                    tdProps.dangerouslySetInnerHTML = { __html: this.props.children.toString() };
+                } else {
+                    tdProps.children = data;
+                }
+            }
+
+            return React.DOM.td(tdProps);
+        }
+    });
+
+
+    var Tr = exports.Tr = React.createClass({displayName: "Tr",
+        statics: {
+            childNode: Td,
+            dataType: 'object'
+        },
+        render: function() {
+            var children = toArray(React.Children.children(this.props.children));
+
+            if (
+                this.props.data &&
+                    this.props.columns &&
+                        typeof this.props.columns.map === 'function'
+            ) {
+                if (typeof(children.concat) === 'undefined') { console.log(children); }
+
+                children = children.concat(this.props.columns.map(function(column, i) {
+                    if (this.props.data.hasOwnProperty(column.key)) {
+                        var value = this.props.data[column.key];
+                        var props = {};
+
+                        if (
+                            typeof(value) !== 'undefined' &&
+                                value !== null &&
+                                    value.__reactableMeta === true
+                        ) {
+                            props = value.props;
+                            value = value.value;
+                        }
+
+                        return React.createElement(Td, React.__spread({column: column, key: column.key},  props), value);
+                    } else {
+                        return React.createElement(Td, {column: column, key: column.key});
+                    }
+                }.bind(this)));
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return React.DOM.tr(props, children);
+        }
+    });
+
+    var Thead = exports.Thead = React.createClass({displayName: "Thead",
+        getColumns: function() {
+            return React.Children.map(this.props.children, function(th) {
+                if (typeof th.props.children === 'string') {
+                    return th.props.children;
+                } else {
+                    throw new TypeError('<th> must have a string child');
+                }
+            });
+        },
+        handleClickTh: function (column) {
+            this.props.onSort(column.key);
+        },
+        render: function() {
+
+            // Declare the list of Ths
+            var Ths = [];
+            for (var index = 0; index < this.props.columns.length; index++) {
+                var column = this.props.columns[index];
+                var sortClass = '';
+
+                if (this.props.sortableColumns[column.key]) {
+                    sortClass += 'reactable-header-sortable ';
+                }
+
+                if (this.props.sort.column === column.key) {
+                    sortClass += 'reactable-header-sort';
+                    if (this.props.sort.direction === 1) {
+                        sortClass += '-asc';
+                    }
+                    else {
+                        sortClass += '-desc';
+                    }
+                }
+
+                Ths.push(
+                    React.createElement(Th, {className: sortClass, key: index, onClick: this.handleClickTh.bind(this, column)}, 
+                        column.label
+                    )
+                );
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return (
+                React.createElement("thead", React.__spread({},  props), 
+                    this.props.filtering === true ?
+                        React.createElement(Filterer, {
+                            colSpan: this.props.columns.length, 
+                            onFilter: this.props.onFilter, 
+                            placeholder: this.props.filterPlaceholder, 
+                            value: this.props.currentFilter}
+                        ) : '', 
+                    React.createElement("tr", {className: "reactable-column-header"}, Ths)
+                )
+            );
+        }
+    });
+
+    var Th = exports.Th = React.createClass({displayName: "Th",
+        render: function() {
+                var childProps
+            if (this.props.children instanceof Unsafe) {
+                return React.createElement("th", React.__spread({},  filterPropsFrom(this.props), 
+                    {dangerouslySetInnerHTML: {__html: this.props.children.toString()}}))
+            } else {
+                return React.createElement("th", React.__spread({},  filterPropsFrom(this.props)), 
+                    this.props.children
+                );
+            }
+        }
+    });
+
+    var FiltererInput = React.createClass({displayName: "FiltererInput",
+        onChange: function() {
+            this.props.onFilter(this.getDOMNode().value);
+        },
+        render: function() {
+            return (
+                React.createElement("input", {type: "text", 
+                    className: "reactable-filter-input", 
+                    placeholder: this.props.placeholder, 
+                    value: this.props.value, 
+                    onKeyUp: this.onChange, 
+                    onChange: this.onChange})
+            );
+        }
+    });
+
+    var Filterer = React.createClass({displayName: "Filterer",
+        render: function() {
+            if (typeof this.props.colSpan === 'undefined') {
+                throw new TypeError('Must pass a colSpan argument to Filterer');
+            }
+
+            return (
+                React.createElement("tr", {className: "reactable-filterer"}, 
+                    React.createElement("td", {colSpan: this.props.colSpan}, 
+                        React.createElement(FiltererInput, {onFilter: this.props.onFilter, 
+                            value: this.props.value, 
+                            placeholder: this.props.placeholder})
+                    )
+                )
+            );
+        }
+    });
+
+    var Paginator = React.createClass({displayName: "Paginator",
+        render: function() {
+            if (typeof this.props.colSpan === 'undefined') {
+                throw new TypeError('Must pass a colSpan argument to Paginator');
+            }
+
+            if (typeof this.props.numPages === 'undefined') {
+                throw new TypeError('Must pass a non-zero numPages argument to Paginator');
+            }
+
+            if (typeof this.props.currentPage === 'undefined') {
+                throw new TypeError('Must pass a currentPage argument to Paginator');
+            }
+
+            var pageButtons = [];
+            for (var i = 0; i < this.props.numPages; i++) {
+                var pageNum = i;
+                var className = "reactable-page-button";
+                if (this.props.currentPage === i) {
+                    className += " reactable-current-page";
+                }
+
+                pageButtons.push(
+                    React.createElement("a", {className: className, key: i, 
+                        // create function to get around for-loop closure issue
+                        onClick: (function(pageNum) {
+                            return function() {
+                                this.props.onPageChange(pageNum);
+                            }.bind(this);
+                        }.bind(this))(i)}, i + 1)
+                );
+            }
+
+            return (
+                React.createElement("tbody", {className: "reactable-pagination"}, 
+                    React.createElement("tr", null, 
+                        React.createElement("td", {colSpan: this.props.colSpan}, 
+                            pageButtons
+                        )
+                    )
+                )
+            );
+        }
+    });
+
+    var Table = exports.Table = React.createClass({displayName: "Table",
+        // Translate a user defined column array to hold column objects if strings are specified
+        // (e.g. ['column1'] => [{key: 'column1', label: 'column1'}])
+        translateColumnsArray: function(columns) {
+            return columns.map(function(column, i) {
+                if (typeof(column) === 'string') {
+                    return {
+                        key:   column,
+                        label: column
+                    };
+                } else {
+                    if (typeof(column.sortable) !== 'undefined') {
+                        var sortFunction = column.sortable === true ? 'default' : column.sortable;
+                        this._sortable[column.key] = sortFunction;
+                    }
+
+                    return column;
+                }
+            }.bind(this));
+        },
+        parseChildData: function(props) {
+            var data = [];
+
+            // Transform any children back to a data array
+            if (typeof(props.children) !== 'undefined') {
+                React.Children.forEach(props.children, function(child) {
+                    // TODO: figure out a new way to determine the type of a component
+                    /*
+                       if (child.type.ConvenienceConstructor !== Tr) {
+                       return; // (continue)
+                       }
+                       */
+                    if (typeof(child.props) !== 'object') {
+                        return console.warn('Child passed to <Reactable.Table> was not an object: ' + child.toString());
+                    }
+
+                    var childData = child.props.data || {};
+
+                    React.Children.forEach(child.props.children, function(descendant) {
+                        // TODO
+                        /* if (descendant.type.ConvenienceConstructor === Td) { */
+                        if (true) {
+                            if (typeof(descendant.props.column) !== 'undefined') {
+                                var value;
+
+                                if (typeof(descendant.props.data) !== 'undefined') {
+                                    value = descendant.props.data;
+                                } else if (typeof(descendant.props.children) !== 'undefined') {
+                                    value = descendant.props.children;
+                                } else {
+                                    console.warn('exports.Td specified without ' +
+                                                 'a `data` property or children, ' +
+                                                 'ignoring');
+                                    return;
+                                }
+
+                                childData[descendant.props.column] = {
+                                    value: value,
+                                    props: filterPropsFrom(descendant.props),
+                                    __reactableMeta: true
+                                };
+                            } else {
+                                console.warn('exports.Td specified without a ' +
+                                             '`column` property, ignoring');
+                            }
+                        }
+                    });
+
+                    data.push({
+                        data: childData,
+                        props: filterPropsFrom(child.props),
+                        __reactableMeta: true
+                    });
+                }.bind(this));
+            }
+
+            return data;
+        },
+
+        initialize: function(props) {
+            this.data = props.data || [];
+            this.data = this.data.concat(this.parseChildData(props));
+            this.initializeSorts(props);
+        },
+
+        initializeSorts: function() {
+            this._sortable = {};
+            // Transform sortable properties into a more friendly list
+            for (var i in this.props.sortable) {
+                var column = this.props.sortable[i];
+                var columnName, sortFunction;
+
+                if (column instanceof Object) {
+                    if (typeof(column.column) !== 'undefined') {
+                        columnName = column.column;
+                    } else {
+                        console.warn('Sortable column specified without column name');
+                        return;
+                    }
+
+                    if (typeof(column.sortFunction) === 'function') {
+                        sortFunction = column.sortFunction;
+                    } else {
+                        sortFunction = 'default';
+                    }
+                } else {
+                    columnName      = column;
+                    sortFunction    = 'default';
+                }
+
+                this._sortable[columnName] = sortFunction;
+            }
+        },
+
+        getDefaultProps: function() {
+            var defaultProps = {
+                sortBy: false,
+                defaultSort: false,
+                itemsPerPage: 0,
+            };
+            return defaultProps;
+        },
+
+        getInitialState: function() {
+            var initialState = {
+                currentPage: 0,
+                currentSort: {
+                    column: null,
+                    direction: 1
+                },
+                filter: ''
+            };
+
+            // Set the state of the current sort to the default sort
+            if (this.props.sortBy !== false || this.props.defaultSort !== false) {
+                var sortingColumn = this.props.sortBy || this.props.defaultSort;
+                initialState.currentSort = this.getCurrentSort(sortingColumn);
+            }
+            return initialState;
+        },
+
+        getCurrentSort: function(column) {
+            var columnName, sortDirection;
+
+            if (column instanceof Object) {
+                if (typeof(column.column) !== 'undefined') {
+                    columnName = column.column;
+                } else {
+                    console.warn('Default column specified without column name');
+                    return;
+                }
+
+                if (typeof(column.direction) !== 'undefined') {
+                    if (column.direction === 1 || column.direction === 'asc') {
+                        sortDirection = 1;
+                    } else if (column.direction === -1 || column.direction === 'desc') {
+                        sortDirection = -1;
+                    } else {
+                        console.warn('Invalid default sort specified.  Defaulting to ascending');
+                        sortDirection = 1;
+                    }
+                } else {
+                    sortDirection = 1;
+                }
+            } else {
+                columnName      = column;
+                sortDirection   = 1;
+            }
+
+            return {
+                column: columnName,
+                direction: sortDirection
+            };
+        },
+
+        updateCurrentSort: function(sortBy) {
+            if (sortBy !== false &&
+                sortBy.column !== this.state.currentSort.column &&
+                    sortBy.direction !== this.state.currentSort.direction) {
+
+                this.setState({ currentSort: this.getCurrentSort(sortBy) });
+            }
+        },
+
+        componentWillMount: function() {
+            this.initialize(this.props);
+            this.sortByCurrentSort();
+        },
+        componentWillReceiveProps: function(nextProps) {
+            this.initialize(nextProps);
+            this.updateCurrentSort(nextProps.sortBy);
+            this.sortByCurrentSort();
+        },
+        onPageChange: function(page) {
+            this.setState({ currentPage: page });
+        },
+        filterBy: function(filter) {
+            this.setState({ filter: filter });
+        },
+        applyFilter: function(filter, children) {
+            // Helper function to apply filter text to a list of table rows
+            filter = filter.toLowerCase();
+            var matchedChildren = [];
+
+            for (var i = 0; i < children.length; i++) {
+                var data = children[i].props.data;
+
+                for (var j = 0; j < this.props.filterable.length; j++) {
+                    var filterColumn = this.props.filterable[j];
+
+                    if (
+                        typeof(data[filterColumn]) !== 'undefined' &&
+                            extractDataFrom(data, filterColumn).toString().toLowerCase().indexOf(filter) > -1
+                    ) {
+                        matchedChildren.push(children[i]);
+                        break;
+                    }
+                }
+            }
+
+            return matchedChildren;
+        },
+        sortByCurrentSort: function(){
+            // Apply a sort function according to the current sort in the state.
+            // This allows us to perform a default sort even on a non sortable column.
+            var currentSort = this.state.currentSort;
+
+            if (currentSort.column === null) {
+                return;
+            }
+
+            this.data.sort(function(a, b){
+                var keyA = extractDataFrom(a, currentSort.column);
+                keyA = (keyA instanceof Unsafe) ? keyA.toString() : keyA || '';
+                var keyB = extractDataFrom(b, currentSort.column);
+                keyB = (keyB instanceof Unsafe) ? keyB.toString() : keyB || '';
+
+                // Default sort
+                if (
+                    typeof(this._sortable[currentSort.column]) === 'undefined' ||
+                        this._sortable[currentSort.column] === 'default'
+                ) {
+
+                    // Reverse direction if we're doing a reverse sort
+                    if (keyA < keyB) {
+                        return -1 * currentSort.direction;
+                    }
+
+                    if (keyA > keyB) {
+                        return 1 * currentSort.direction;
+                    }
+
+                    return 0;
+                } else {
+                    // Reverse columns if we're doing a reverse sort
+                    if (currentSort.direction === 1) {
+                        return this._sortable[currentSort.column](keyA, keyB);
+                    } else {
+                        return this._sortable[currentSort.column](keyB, keyA);
+                    }
+                }
+            }.bind(this));
+        },
+        onSort: function(column) {
+            // Don't perform sort on unsortable columns
+            if (typeof(this._sortable[column]) === 'undefined') {
+                return;
+            }
+
+            var currentSort = this.state.currentSort;
+
+            if (currentSort.column === column) {
+                currentSort.direction *= -1;
+            } else {
+                currentSort.column = column;
+                currentSort.direction = 1;
+            }
+
+            // Set the current sort and pass it to the sort function
+            this.setState({ currentSort: currentSort });
+            this.sortByCurrentSort();
+        },
+        render: function() {
+            var children = [];
+            var columns;
+            var userColumnsSpecified = false;
+
+            if (
+                this.props.children &&
+                    this.props.children.length > 0 &&
+                        this.props.children[0].type.ConvenienceConstructor === Thead
+            ) {
+                columns = this.props.children[0].getColumns();
+            } else {
+                columns = this.props.columns || [];
+            }
+
+            if (columns.length > 0) {
+                userColumnsSpecified = true;
+                columns = this.translateColumnsArray(columns);
+            }
+
+            // Build up table rows
+            if (this.data && typeof this.data.map === 'function') {
+                // Build up the columns array
+                children = children.concat(this.data.map(function(rawData, i) {
+                    var data = rawData;
+                    var props = {};
+                    if (rawData.__reactableMeta === true) {
+                        data = rawData.data;
+                        props = rawData.props;
+                    }
+
+                    // Loop through the keys in each data row and build a td for it
+                    for (var k in data) {
+                        if (data.hasOwnProperty(k)) {
+                            // Update the columns array with the data's keys if columns were not
+                            // already specified
+                            if (userColumnsSpecified === false) {
+                                var column = {
+                                    key:   k,
+                                    label: k
+                                };
+
+                                // Only add a new column if it doesn't already exist in the columns array
+                                if (
+                                    columns.find(function(element) {
+                                    return element.key === column.key;
+                                }) === undefined
+                                ) {
+                                    columns.push(column);
+                                }
+                            }
+                        }
+                    }
+
+                    return (
+                        React.createElement(Tr, React.__spread({columns: columns, key: i, data: data},  props))
+                    );
+                }.bind(this)));
+            }
+
+            if (this.props.sortable === true) {
+                for (var i = 0; i < columns.length; i++) {
+                    this._sortable[columns[i].key] = 'default';
+                }
+            }
+
+            // Determine if we render the filter box
+            var filtering = false;
+            if (
+                this.props.filterable &&
+                    Array.isArray(this.props.filterable) &&
+                        this.props.filterable.length > 0
+            ) {
+                filtering = true;
+            }
+
+            // Apply filters
+            var filteredChildren = children;
+            if (this.state.filter !== '') {
+                filteredChildren = this.applyFilter(this.state.filter, filteredChildren);
+            }
+
+            // Determine pagination properties and which columns to display
+            var itemsPerPage = 0;
+            var pagination = false;
+            var numPages;
+            var currentPage = this.state.currentPage;
+
+            var currentChildren = filteredChildren;
+            if (this.props.itemsPerPage > 0) {
+                itemsPerPage = this.props.itemsPerPage;
+                numPages = Math.ceil(filteredChildren.length / itemsPerPage);
+
+                if (currentPage > numPages - 1) {
+                    currentPage = numPages - 1;
+                }
+
+                pagination = true;
+                currentChildren = filteredChildren.slice(
+                    currentPage * itemsPerPage,
+                    (currentPage + 1) * itemsPerPage
+                );
+            }
+
+            // Manually transfer props
+            var props = filterPropsFrom(this.props);
+
+            return React.createElement("table", React.__spread({},  props), [
+                (columns && columns.length > 0 ?
+                 React.createElement(Thead, {columns: columns, 
+                     filtering: filtering, 
+                     onFilter: this.filterBy, 
+                     filterPlaceholder: this.props.filterPlaceholder, 
+                     currentFilter: this.state.filter, 
+                     sort: this.state.currentSort, 
+                     sortableColumns: this._sortable, 
+                     onSort: this.onSort, 
+                     key: "thead"})
+                 : null
+                ),
+                React.createElement("tbody", {className: "reactable-data", key: "tbody"}, 
+                    currentChildren
+                ),
+                (pagination === true ?
+                 React.createElement(Paginator, {colSpan: columns.length, 
+                     numPages: numPages, 
+                     currentPage: currentPage, 
+                     onPageChange: this.onPageChange, 
+                     key: "paginator"})
+                 : null
+                )
+            ]);
+        }
+    });
+
+    function toArray(obj) {
+        var ret = [];
+        for (var attr in obj) {
+            ret[attr] = obj;
+        }
+
+        return ret;
+    }
+
+    function filterPropsFrom(baseProps) {
+        baseProps = baseProps || {};
+        var props = {};
+        for (var key in baseProps) {
+            if (!(key in internalProps)) {
+                props[key] = baseProps[key];
+            }
+        }
+        return props;
+    }
+
+    function extractDataFrom(key, column) {
+        var value;
+        if (
+            typeof(key) !== 'undefined' &&
+                key !== null &&
+                    key.__reactableMeta === true
+        ) {
+            value = key.data[column];
+        } else {
+            value = key[column];
+        }
+
+        if (
+            typeof(value) !== 'undefined' &&
+                value !== null &&
+                    value.__reactableMeta === true
+        ) {
+            value = (typeof(value.props.value) !== 'undefined' && value.props.value !== null) ?
+                value.props.value : value.value;
+        }
+
+        return value;
+    }
+
+    var internalProps = {
+        columns: true,
+        sortable: true,
+        filterable: true,
+        sortBy: true,
+        defaultSort: true,
+        itemsPerPage: true,
+        childNode: true,
+        data: true,
+        children: true
+    };
+
+    return exports;
+}));
diff --git a/webcore/test/simple-result/module.js b/webcore/test/simple-result/module.js
new file mode 100644
index 0000000..e88661a
--- /dev/null
+++ b/webcore/test/simple-result/module.js
@@ -0,0 +1,926 @@
+(function(f) {
+    if (typeof exports === "object" && typeof module !== "undefined") {
+        module.exports = f();
+    } else if (typeof define === "function" && define.amd) {
+        define([], f);
+    } else {
+        var g;
+        if (typeof window !== "undefined") {
+            g = window;
+        } else if (typeof global !== "undefined") {
+            g = global;
+        } else if (typeof self !== "undefined") {
+            g = self;
+        } else {
+            g = this;
+        }
+        g.simpleResult = f();
+    }
+})(function() {
+    var define, module, exports;
+    return function e(t, n, r) {
+        function s(o, u) {
+            if (!n[o]) {
+                if (!t[o]) {
+                    var a = typeof require == "function" && require;
+                    if (!u && a) return a(o, !0);
+                    if (i) return i(o, !0);
+                    var f = new Error("Cannot find module '" + o + "'");
+                    throw f.code = "MODULE_NOT_FOUND", f;
+                }
+                var l = n[o] = {
+                    exports: {}
+                };
+                t[o][0].call(l.exports, function(e) {
+                    var n = t[o][1][e];
+                    return s(n ? n : e);
+                }, l, l.exports, e, t, n, r);
+            }
+            return n[o].exports;
+        }
+        var i = typeof require == "function" && require;
+        for (var o = 0; o < r.length; o++) s(r[o]);
+        return s;
+    }({
+        1: [ function(require, module, exports) {
+            // simple-result.jsx - Simple Result Module file (React JSX)
+            // JSHint directives
+            /* global require: false */
+            /* global document: false */
+            /* global console: false */
+            /* global module: false */
+            // external dependencies
+            var React = require("react");
+            // bundled dependencies
+            var Reactable = require("reactable");
+            var ResultTable = React.createClass({
+                displayName: "ResultTable",
+                getInitialState: function() {
+                    return {
+                        results: [],
+                        resultNum: null,
+                        requestTime: 0
+                    };
+                },
+                onChange: function(e) {},
+                shouldComponentUpdate: function(nextProps, nextState) {
+                    return nextProps.id !== this.props.id || nextState.requestTime - this.state.requestTime > 0;
+                },
+                componentWillUpdate: function(nextProps, nextState) {},
+                render: function() {
+                    var Table = Reactable.Table;
+                    return React.createElement("div", null, React.createElement(Table, {
+                        className: "table",
+                        data: this.state.results,
+                        itemsPerPage: 10
+                    }));
+                }
+            });
+            module.exports = function() {
+                var resultTable;
+                var handler;
+                this.render = function(parent) {
+                    resultTable = React.createElement(ResultTable, null);
+                    handler = React.render(resultTable, parent);
+                };
+                this.onResult = function(data, requestTime, options) {
+                    if (!handler) {
+                        console.error("onResult was invoked before the result plugin was rendered, ignoring");
+                        return;
+                    }
+                    console.log("[onResult] Got ", data.numResults, " entries.");
+                    if (data.numResults === 0) {
+                        handler.setState({
+                            results: {},
+                            n: 0,
+                            elapsedTime: data.elapsedTime,
+                            requestTime: requestTime
+                        });
+                        return;
+                    }
+                    for (var i = 0; i < data.results.length; i++) {
+                        var fields = data.results[i].fields;
+                        if (fields) {
+                            delete data.results[i].fields;
+                            for (var fname in fields) {
+                                data.results[i][fname] = fields[fname];
+                            }
+                        }
+                    }
+                    handler.setState({
+                        results: data.results,
+                        n: data.numResults,
+                        elapsedTime: data.elapsedTime,
+                        requestTime: requestTime
+                    });
+                };
+            };
+        }, {
+            react: "react",
+            reactable: 2
+        } ],
+        2: [ function(require, module, exports) {
+            (function(root, factory) {
+                if (typeof define === "function" && define.amd) {
+                    // AMD. Register as an anonymous module.
+                    define([ "react" ], factory);
+                } else if (typeof exports === "object") {
+                    // Node. Does not work with strict CommonJS, but
+                    // only CommonJS-like environments that support module.exports,
+                    // like Node.
+                    module.exports = factory(require("react"));
+                } else {
+                    // Browser globals (root is window)
+                    root.Reactable = factory(root.React);
+                }
+            })(this, function(React) {
+                "use strict";
+                var exports = {};
+                // Array.prototype.map polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill
+                // Production steps of ECMA-262, Edition 5, 15.4.4.19
+                // Reference: http://es5.github.io/#x15.4.4.19
+                if (!Array.prototype.map) {
+                    Array.prototype.map = function(callback, thisArg) {
+                        var T, A, k;
+                        if (this === null) {
+                            throw new TypeError(" this is null or not defined");
+                        }
+                        var O = Object(this);
+                        var len = O.length >>> 0;
+                        if (typeof callback !== "function") {
+                            throw new TypeError(callback + " is not a function");
+                        }
+                        if (arguments.length > 1) {
+                            T = thisArg;
+                        }
+                        A = new Array(len);
+                        k = 0;
+                        while (k < len) {
+                            var kValue, mappedValue;
+                            if (k in O) {
+                                kValue = O[k];
+                                mappedValue = callback.call(T, kValue, k, O);
+                                A[k] = mappedValue;
+                            }
+                            k++;
+                        }
+                        return A;
+                    };
+                }
+                // Array.prototype.indexOf polyfill for IE8
+                if (!Array.prototype.indexOf) {
+                    Array.prototype.indexOf = function(elt) {
+                        var len = this.length >>> 0;
+                        var from = Number(arguments[1]) || 0;
+                        from = from < 0 ? Math.ceil(from) : Math.floor(from);
+                        if (from < 0) {
+                            from += len;
+                        }
+                        for (;from < len; from++) {
+                            if (from in this && this[from] === elt) {
+                                return from;
+                            }
+                        }
+                        return -1;
+                    };
+                }
+                // Array.prototype.find polyfill - see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
+                if (!Array.prototype.find) {
+                    Object.defineProperty(Array.prototype, "find", {
+                        enumerable: false,
+                        configurable: true,
+                        writable: true,
+                        value: function(predicate) {
+                            if (this === null) {
+                                throw new TypeError("Array.prototype.find called on null or undefined");
+                            }
+                            if (typeof predicate !== "function") {
+                                throw new TypeError("predicate must be a function");
+                            }
+                            var list = Object(this);
+                            var length = list.length >>> 0;
+                            var thisArg = arguments[1];
+                            var value;
+                            for (var i = 0; i < length; i++) {
+                                if (i in list) {
+                                    value = list[i];
+                                    if (predicate.call(thisArg, value, i, list)) {
+                                        return value;
+                                    }
+                                }
+                            }
+                            return undefined;
+                        }
+                    });
+                }
+                if (!Array.isArray) {
+                    Array.isArray = function(value) {
+                        return Object.prototype.toString.call(value) === "[object Array]";
+                    };
+                }
+                if (!Object.assign) {
+                    Object.defineProperty(Object, "assign", {
+                        enumerable: false,
+                        configurable: true,
+                        writable: true,
+                        value: function(target, firstSource) {
+                            if (target === undefined || target === null) throw new TypeError("Cannot convert first argument to object");
+                            var to = Object(target);
+                            for (var i = 1; i < arguments.length; i++) {
+                                var nextSource = arguments[i];
+                                if (nextSource === undefined || nextSource === null) continue;
+                                var keysArray = Object.keys(Object(nextSource));
+                                for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
+                                    var nextKey = keysArray[nextIndex];
+                                    var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
+                                    if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey];
+                                }
+                            }
+                            return to;
+                        }
+                    });
+                }
+                function Unsafe(content) {
+                    this.content = content;
+                }
+                Unsafe.prototype.toString = function() {
+                    return this.content;
+                };
+                function stringable(thing) {
+                    return thing !== null && typeof thing !== "undefined" && typeof (thing.toString === "function");
+                }
+                // this is a bit hacky - it'd be nice if React exposed an API for this
+                function isReactComponent(thing) {
+                    return thing !== null && typeof thing === "object" && typeof thing.props !== "undefined";
+                }
+                React.Children.children = function(children) {
+                    return React.Children.map(children, function(x) {
+                        return x;
+                    }) || [];
+                };
+                exports.unsafe = function(str) {
+                    return new Unsafe(str);
+                };
+                exports.Sort = {
+                    Numeric: function(a, b) {
+                        var valA = parseFloat(a.toString().replace(",", ""));
+                        var valB = parseFloat(b.toString().replace(",", ""));
+                        // Sort non-numeric values alphabetically at the bottom of the list
+                        if (isNaN(valA) && isNaN(valB)) {
+                            valA = a;
+                            valB = b;
+                        } else {
+                            if (isNaN(valA)) {
+                                return 1;
+                            }
+                            if (isNaN(valB)) {
+                                return -1;
+                            }
+                        }
+                        if (valA < valB) {
+                            return -1;
+                        }
+                        if (valA > valB) {
+                            return 1;
+                        }
+                        return 0;
+                    },
+                    NumericInteger: function(a, b) {
+                        if (isNaN(a) || isNaN(b)) {
+                            return a > b ? 1 : -1;
+                        }
+                        return a - b;
+                    },
+                    Currency: function(a, b) {
+                        // Parse out dollar signs, then do a regular numeric sort
+                        // TODO: handle non-American currency
+                        if (a[0] === "$") {
+                            a = a.substring(1);
+                        }
+                        if (b[0] === "$") {
+                            b = b.substring(1);
+                        }
+                        return exports.Sort.Numeric(a, b);
+                    },
+                    Date: function(a, b) {
+                        // Note: this function tries to do a standard javascript string -> date conversion
+                        // If you need more control over the date string format, consider using a different
+                        // date library and writing your own function
+                        var valA = Date.parse(a);
+                        var valB = Date.parse(b);
+                        // Handle non-date values with numeric sort
+                        // Sort non-numeric values alphabetically at the bottom of the list
+                        if (isNaN(valA) || isNaN(valB)) {
+                            return exports.Sort.Numeric(a, b);
+                        }
+                        if (valA > valB) {
+                            return 1;
+                        }
+                        if (valB > valA) {
+                            return -1;
+                        }
+                        return 0;
+                    },
+                    CaseInsensitive: function(a, b) {
+                        return a.toLowerCase().localeCompare(b.toLowerCase());
+                    }
+                };
+                var Td = exports.Td = React.createClass({
+                    displayName: "Td",
+                    handleClick: function(e) {
+                        if (typeof this.props.handleClick === "function") {
+                            return this.props.handleClick(e, this);
+                        }
+                    },
+                    render: function() {
+                        var tdProps = {
+                            className: this.props.className,
+                            onClick: this.handleClick
+                        };
+                        // Attach any properties on the column to this Td object to allow things like custom event handlers
+                        if (typeof this.props.column === "object") {
+                            for (var key in this.props.column) {
+                                if (key !== "key" && key !== "name") {
+                                    tdProps[key] = this.props.column[key];
+                                }
+                            }
+                        }
+                        var data = this.props.data;
+                        if (typeof this.props.children !== "undefined") {
+                            if (isReactComponent(this.props.children)) {
+                                data = this.props.children;
+                            } else if (typeof this.props.data === "undefined" && stringable(this.props.children)) {
+                                data = this.props.children.toString();
+                            }
+                            if (this.props.children instanceof Unsafe) {
+                                tdProps.dangerouslySetInnerHTML = {
+                                    __html: this.props.children.toString()
+                                };
+                            } else {
+                                tdProps.children = data;
+                            }
+                        }
+                        return React.DOM.td(tdProps);
+                    }
+                });
+                var Tr = exports.Tr = React.createClass({
+                    displayName: "Tr",
+                    statics: {
+                        childNode: Td,
+                        dataType: "object"
+                    },
+                    render: function() {
+                        var children = toArray(React.Children.children(this.props.children));
+                        if (this.props.data && this.props.columns && typeof this.props.columns.map === "function") {
+                            if (typeof children.concat === "undefined") {
+                                console.log(children);
+                            }
+                            children = children.concat(this.props.columns.map(function(column, i) {
+                                if (this.props.data.hasOwnProperty(column.key)) {
+                                    var value = this.props.data[column.key];
+                                    var props = {};
+                                    if (typeof value !== "undefined" && value !== null && value.__reactableMeta === true) {
+                                        props = value.props;
+                                        value = value.value;
+                                    }
+                                    return React.createElement(Td, React.__spread({
+                                        column: column,
+                                        key: column.key
+                                    }, props), value);
+                                } else {
+                                    return React.createElement(Td, {
+                                        column: column,
+                                        key: column.key
+                                    });
+                                }
+                            }.bind(this)));
+                        }
+                        // Manually transfer props
+                        var props = filterPropsFrom(this.props);
+                        return React.DOM.tr(props, children);
+                    }
+                });
+                var Thead = exports.Thead = React.createClass({
+                    displayName: "Thead",
+                    getColumns: function() {
+                        return React.Children.map(this.props.children, function(th) {
+                            if (typeof th.props.children === "string") {
+                                return th.props.children;
+                            } else {
+                                throw new TypeError("<th> must have a string child");
+                            }
+                        });
+                    },
+                    handleClickTh: function(column) {
+                        this.props.onSort(column.key);
+                    },
+                    render: function() {
+                        // Declare the list of Ths
+                        var Ths = [];
+                        for (var index = 0; index < this.props.columns.length; index++) {
+                            var column = this.props.columns[index];
+                            var sortClass = "";
+                            if (this.props.sortableColumns[column.key]) {
+                                sortClass += "reactable-header-sortable ";
+                            }
+                            if (this.props.sort.column === column.key) {
+                                sortClass += "reactable-header-sort";
+                                if (this.props.sort.direction === 1) {
+                                    sortClass += "-asc";
+                                } else {
+                                    sortClass += "-desc";
+                                }
+                            }
+                            Ths.push(React.createElement(Th, {
+                                className: sortClass,
+                                key: index,
+                                onClick: this.handleClickTh.bind(this, column)
+                            }, column.label));
+                        }
+                        // Manually transfer props
+                        var props = filterPropsFrom(this.props);
+                        return React.createElement("thead", React.__spread({}, props), this.props.filtering === true ? React.createElement(Filterer, {
+                            colSpan: this.props.columns.length,
+                            onFilter: this.props.onFilter,
+                            value: this.props.currentFilter
+                        }) : "", React.createElement("tr", {
+                            className: "reactable-column-header"
+                        }, Ths));
+                    }
+                });
+                var Th = exports.Th = React.createClass({
+                    displayName: "Th",
+                    render: function() {
+                        var childProps;
+                        if (this.props.children instanceof Unsafe) {
+                            return React.createElement("th", React.__spread({}, filterPropsFrom(this.props), {
+                                dangerouslySetInnerHTML: {
+                                    __html: this.props.children.toString()
+                                }
+                            }));
+                        } else {
+                            return React.createElement("th", React.__spread({}, filterPropsFrom(this.props)), this.props.children);
+                        }
+                    }
+                });
+                var FiltererInput = React.createClass({
+                    displayName: "FiltererInput",
+                    onChange: function() {
+                        this.props.onFilter(this.getDOMNode().value);
+                    },
+                    render: function() {
+                        return React.createElement("input", {
+                            type: "text",
+                            className: "reactable-filter-input",
+                            value: this.props.value,
+                            onKeyUp: this.onChange,
+                            onChange: this.onChange
+                        });
+                    }
+                });
+                var Filterer = React.createClass({
+                    displayName: "Filterer",
+                    render: function() {
+                        if (typeof this.props.colSpan === "undefined") {
+                            throw new TypeError("Must pass a colSpan argument to Filterer");
+                        }
+                        return React.createElement("tr", {
+                            className: "reactable-filterer"
+                        }, React.createElement("td", {
+                            colSpan: this.props.colSpan
+                        }, React.createElement(FiltererInput, {
+                            onFilter: this.props.onFilter,
+                            value: this.props.value
+                        })));
+                    }
+                });
+                var Paginator = React.createClass({
+                    displayName: "Paginator",
+                    render: function() {
+                        if (typeof this.props.colSpan === "undefined") {
+                            throw new TypeError("Must pass a colSpan argument to Paginator");
+                        }
+                        if (typeof this.props.numPages === "undefined") {
+                            throw new TypeError("Must pass a non-zero numPages argument to Paginator");
+                        }
+                        if (typeof this.props.currentPage === "undefined") {
+                            throw new TypeError("Must pass a currentPage argument to Paginator");
+                        }
+                        var pageButtons = [];
+                        for (var i = 0; i < this.props.numPages; i++) {
+                            var pageNum = i;
+                            var className = "reactable-page-button";
+                            if (this.props.currentPage === i) {
+                                className += " reactable-current-page";
+                            }
+                            pageButtons.push(React.createElement("a", {
+                                className: className,
+                                key: i,
+                                // create function to get around for-loop closure issue
+                                onClick: function(pageNum) {
+                                    return function() {
+                                        this.props.onPageChange(pageNum);
+                                    }.bind(this);
+                                }.bind(this)(i)
+                            }, i + 1));
+                        }
+                        return React.createElement("tbody", {
+                            className: "reactable-pagination"
+                        }, React.createElement("tr", null, React.createElement("td", {
+                            colSpan: this.props.colSpan
+                        }, pageButtons)));
+                    }
+                });
+                var Table = exports.Table = React.createClass({
+                    displayName: "Table",
+                    // Translate a user defined column array to hold column objects if strings are specified
+                    // (e.g. ['column1'] => [{key: 'column1', label: 'column1'}])
+                    translateColumnsArray: function(columns) {
+                        return columns.map(function(column, i) {
+                            if (typeof column === "string") {
+                                return {
+                                    key: column,
+                                    label: column
+                                };
+                            } else {
+                                if (typeof column.sortable !== "undefined") {
+                                    var sortFunction = column.sortable === true ? "default" : column.sortable;
+                                    this._sortable[column.key] = sortFunction;
+                                }
+                                return column;
+                            }
+                        }.bind(this));
+                    },
+                    parseChildData: function(props) {
+                        var data = [];
+                        // Transform any children back to a data array
+                        if (typeof props.children !== "undefined") {
+                            React.Children.forEach(props.children, function(child) {
+                                // TODO: figure out a new way to determine the type of a component
+                                /*
+                       if (child.type.ConvenienceConstructor !== Tr) {
+                       return; // (continue)
+                       }
+                       */
+                                if (typeof child.props !== "object") {
+                                    return console.warn("Child passed to <Reactable.Table> was not an object: " + child.toString());
+                                }
+                                var childData = child.props.data || {};
+                                React.Children.forEach(child.props.children, function(descendant) {
+                                    // TODO
+                                    /* if (descendant.type.ConvenienceConstructor === Td) { */
+                                    if (true) {
+                                        if (typeof descendant.props.column !== "undefined") {
+                                            var value;
+                                            if (typeof descendant.props.data !== "undefined") {
+                                                value = descendant.props.data;
+                                            } else if (typeof descendant.props.children !== "undefined") {
+                                                value = descendant.props.children;
+                                            } else {
+                                                console.warn("exports.Td specified without " + "a `data` property or children, " + "ignoring");
+                                                return;
+                                            }
+                                            childData[descendant.props.column] = {
+                                                value: value,
+                                                props: filterPropsFrom(descendant.props),
+                                                __reactableMeta: true
+                                            };
+                                        } else {
+                                            console.warn("exports.Td specified without a " + "`column` property, ignoring");
+                                        }
+                                    }
+                                });
+                                data.push({
+                                    data: childData,
+                                    props: filterPropsFrom(child.props),
+                                    __reactableMeta: true
+                                });
+                            }.bind(this));
+                        }
+                        return data;
+                    },
+                    initialize: function(props) {
+                        this.data = props.data || [];
+                        this.data = this.data.concat(this.parseChildData(props));
+                        this.initializeSorts(props);
+                    },
+                    initializeSorts: function() {
+                        this._sortable = {};
+                        // Transform sortable properties into a more friendly list
+                        for (var i in this.props.sortable) {
+                            var column = this.props.sortable[i];
+                            var columnName, sortFunction;
+                            if (column instanceof Object) {
+                                if (typeof column.column !== "undefined") {
+                                    columnName = column.column;
+                                } else {
+                                    console.warn("Sortable column specified without column name");
+                                    return;
+                                }
+                                if (typeof column.sortFunction === "function") {
+                                    sortFunction = column.sortFunction;
+                                } else {
+                                    sortFunction = "default";
+                                }
+                            } else {
+                                columnName = column;
+                                sortFunction = "default";
+                            }
+                            this._sortable[columnName] = sortFunction;
+                        }
+                    },
+                    getDefaultProps: function() {
+                        var defaultProps = {
+                            sortBy: false,
+                            defaultSort: false,
+                            itemsPerPage: 0
+                        };
+                        return defaultProps;
+                    },
+                    getInitialState: function() {
+                        var initialState = {
+                            currentPage: 0,
+                            currentSort: {
+                                column: null,
+                                direction: 1
+                            },
+                            filter: ""
+                        };
+                        // Set the state of the current sort to the default sort
+                        if (this.props.sortBy !== false || this.props.defaultSort !== false) {
+                            var sortingColumn = this.props.sortBy || this.props.defaultSort;
+                            initialState.currentSort = this.getCurrentSort(sortingColumn);
+                        }
+                        return initialState;
+                    },
+                    getCurrentSort: function(column) {
+                        var columnName, sortDirection;
+                        if (column instanceof Object) {
+                            if (typeof column.column !== "undefined") {
+                                columnName = column.column;
+                            } else {
+                                console.warn("Default column specified without column name");
+                                return;
+                            }
+                            if (typeof column.direction !== "undefined") {
+                                if (column.direction === 1 || column.direction === "asc") {
+                                    sortDirection = 1;
+                                } else if (column.direction === -1 || column.direction === "desc") {
+                                    sortDirection = -1;
+                                } else {
+                                    console.warn("Invalid default sort specified.  Defaulting to ascending");
+                                    sortDirection = 1;
+                                }
+                            } else {
+                                sortDirection = 1;
+                            }
+                        } else {
+                            columnName = column;
+                            sortDirection = 1;
+                        }
+                        return {
+                            column: columnName,
+                            direction: sortDirection
+                        };
+                    },
+                    updateCurrentSort: function(sortBy) {
+                        if (sortBy !== false && sortBy.column !== this.state.currentSort.column && sortBy.direction !== this.state.currentSort.direction) {
+                            this.setState({
+                                currentSort: this.getCurrentSort(sortBy)
+                            });
+                        }
+                    },
+                    componentWillMount: function() {
+                        this.initialize(this.props);
+                        this.sortByCurrentSort();
+                    },
+                    componentWillReceiveProps: function(nextProps) {
+                        this.initialize(nextProps);
+                        this.updateCurrentSort(nextProps.sortBy);
+                        this.sortByCurrentSort();
+                    },
+                    onPageChange: function(page) {
+                        this.setState({
+                            currentPage: page
+                        });
+                    },
+                    filterBy: function(filter) {
+                        this.setState({
+                            filter: filter
+                        });
+                    },
+                    applyFilter: function(filter, children) {
+                        // Helper function to apply filter text to a list of table rows
+                        filter = filter.toLowerCase();
+                        var matchedChildren = [];
+                        for (var i = 0; i < children.length; i++) {
+                            var data = children[i].props.data;
+                            for (var j = 0; j < this.props.filterable.length; j++) {
+                                var filterColumn = this.props.filterable[j];
+                                if (typeof data[filterColumn] !== "undefined" && extractDataFrom(data, filterColumn).toString().toLowerCase().indexOf(filter) > -1) {
+                                    matchedChildren.push(children[i]);
+                                    break;
+                                }
+                            }
+                        }
+                        return matchedChildren;
+                    },
+                    sortByCurrentSort: function() {
+                        // Apply a sort function according to the current sort in the state.
+                        // This allows us to perform a default sort even on a non sortable column.
+                        var currentSort = this.state.currentSort;
+                        if (currentSort.column === null) {
+                            return;
+                        }
+                        this.data.sort(function(a, b) {
+                            var keyA = extractDataFrom(a, currentSort.column);
+                            keyA = keyA instanceof Unsafe ? keyA.toString() : keyA || "";
+                            var keyB = extractDataFrom(b, currentSort.column);
+                            keyB = keyB instanceof Unsafe ? keyB.toString() : keyB || "";
+                            // Default sort
+                            if (typeof this._sortable[currentSort.column] === "undefined" || this._sortable[currentSort.column] === "default") {
+                                // Reverse direction if we're doing a reverse sort
+                                if (keyA < keyB) {
+                                    return -1 * currentSort.direction;
+                                }
+                                if (keyA > keyB) {
+                                    return 1 * currentSort.direction;
+                                }
+                                return 0;
+                            } else {
+                                // Reverse columns if we're doing a reverse sort
+                                if (currentSort.direction === 1) {
+                                    return this._sortable[currentSort.column](keyA, keyB);
+                                } else {
+                                    return this._sortable[currentSort.column](keyB, keyA);
+                                }
+                            }
+                        }.bind(this));
+                    },
+                    onSort: function(column) {
+                        // Don't perform sort on unsortable columns
+                        if (typeof this._sortable[column] === "undefined") {
+                            return;
+                        }
+                        var currentSort = this.state.currentSort;
+                        if (currentSort.column === column) {
+                            currentSort.direction *= -1;
+                        } else {
+                            currentSort.column = column;
+                            currentSort.direction = 1;
+                        }
+                        // Set the current sort and pass it to the sort function
+                        this.setState({
+                            currentSort: currentSort
+                        });
+                        this.sortByCurrentSort();
+                    },
+                    render: function() {
+                        var children = [];
+                        var columns;
+                        var userColumnsSpecified = false;
+                        if (this.props.children && this.props.children.length > 0 && this.props.children[0].type.ConvenienceConstructor === Thead) {
+                            columns = this.props.children[0].getColumns();
+                        } else {
+                            columns = this.props.columns || [];
+                        }
+                        if (columns.length > 0) {
+                            userColumnsSpecified = true;
+                            columns = this.translateColumnsArray(columns);
+                        }
+                        // Build up table rows
+                        if (this.data && typeof this.data.map === "function") {
+                            // Build up the columns array
+                            children = children.concat(this.data.map(function(rawData, i) {
+                                var data = rawData;
+                                var props = {};
+                                if (rawData.__reactableMeta === true) {
+                                    data = rawData.data;
+                                    props = rawData.props;
+                                }
+                                // Loop through the keys in each data row and build a td for it
+                                for (var k in data) {
+                                    if (data.hasOwnProperty(k)) {
+                                        // Update the columns array with the data's keys if columns were not
+                                        // already specified
+                                        if (userColumnsSpecified === false) {
+                                            var column = {
+                                                key: k,
+                                                label: k
+                                            };
+                                            // Only add a new column if it doesn't already exist in the columns array
+                                            if (columns.find(function(element) {
+                                                return element.key === column.key;
+                                            }) === undefined) {
+                                                columns.push(column);
+                                            }
+                                        }
+                                    }
+                                }
+                                return React.createElement(Tr, React.__spread({
+                                    columns: columns,
+                                    key: i,
+                                    data: data
+                                }, props));
+                            }.bind(this)));
+                        }
+                        if (this.props.sortable === true) {
+                            for (var i = 0; i < columns.length; i++) {
+                                this._sortable[columns[i].key] = "default";
+                            }
+                        }
+                        // Determine if we render the filter box
+                        var filtering = false;
+                        if (this.props.filterable && Array.isArray(this.props.filterable) && this.props.filterable.length > 0) {
+                            filtering = true;
+                        }
+                        // Apply filters
+                        var filteredChildren = children;
+                        if (this.state.filter !== "") {
+                            filteredChildren = this.applyFilter(this.state.filter, filteredChildren);
+                        }
+                        // Determine pagination properties and which columns to display
+                        var itemsPerPage = 0;
+                        var pagination = false;
+                        var numPages;
+                        var currentPage = this.state.currentPage;
+                        var currentChildren = filteredChildren;
+                        if (this.props.itemsPerPage > 0) {
+                            itemsPerPage = this.props.itemsPerPage;
+                            numPages = Math.ceil(filteredChildren.length / itemsPerPage);
+                            if (currentPage > numPages - 1) {
+                                currentPage = numPages - 1;
+                            }
+                            pagination = true;
+                            currentChildren = filteredChildren.slice(currentPage * itemsPerPage, (currentPage + 1) * itemsPerPage);
+                        }
+                        // Manually transfer props
+                        var props = filterPropsFrom(this.props);
+                        return React.createElement("table", React.__spread({}, props), [ columns && columns.length > 0 ? React.createElement(Thead, {
+                            columns: columns,
+                            filtering: filtering,
+                            onFilter: this.filterBy,
+                            currentFilter: this.state.filter,
+                            sort: this.state.currentSort,
+                            sortableColumns: this._sortable,
+                            onSort: this.onSort,
+                            key: "thead"
+                        }) : null, React.createElement("tbody", {
+                            className: "reactable-data",
+                            key: "tbody"
+                        }, currentChildren), pagination === true ? React.createElement(Paginator, {
+                            colSpan: columns.length,
+                            numPages: numPages,
+                            currentPage: currentPage,
+                            onPageChange: this.onPageChange,
+                            key: "paginator"
+                        }) : null ]);
+                    }
+                });
+                function toArray(obj) {
+                    var ret = [];
+                    for (var attr in obj) {
+                        ret[attr] = obj;
+                    }
+                    return ret;
+                }
+                function filterPropsFrom(baseProps) {
+                    baseProps = baseProps || {};
+                    var props = {};
+                    for (var key in baseProps) {
+                        if (!(key in internalProps)) {
+                            props[key] = baseProps[key];
+                        }
+                    }
+                    return props;
+                }
+                function extractDataFrom(key, column) {
+                    var value;
+                    if (typeof key !== "undefined" && key !== null && key.__reactableMeta === true) {
+                        value = key.data[column];
+                    } else {
+                        value = key[column];
+                    }
+                    if (typeof value !== "undefined" && value !== null && value.__reactableMeta === true) {
+                        value = typeof value.props.value !== "undefined" && value.props.value !== null ? value.props.value : value.value;
+                    }
+                    return value;
+                }
+                var internalProps = {
+                    columns: true,
+                    sortable: true,
+                    filterable: true,
+                    sortBy: true,
+                    defaultSort: true,
+                    itemsPerPage: true,
+                    childNode: true,
+                    data: true,
+                    children: true
+                };
+                return exports;
+            });
+        }, {
+            react: "react"
+        } ]
+    }, {}, [ 1 ])(1);
+});
\ No newline at end of file
diff --git a/webcore/test/simple-result/module.js.map b/webcore/test/simple-result/module.js.map
new file mode 100644
index 0000000..c0d09f4
--- /dev/null
+++ b/webcore/test/simple-result/module.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"module.js","sources":["build/module.js"],"names":["e","t","n","r","s","o","u","a","require","i","f","Error","code","l","exports","call","length",1,"module","React","Reactable","ResultTable","createClass","displayName","getInitialState","results","resultNum","requestTime","onChange","shouldComponentUpdate","nextProps","nextState","id","this","props","state","componentWillUpdate","render","Table","createElement","className","data","itemsPerPage","resultTable","handler" [...]
\ No newline at end of file
diff --git a/webcore/test/simple-result/module.min.js b/webcore/test/simple-result/module.min.js
new file mode 100644
index 0000000..a4b42f6
--- /dev/null
+++ b/webcore/test/simple-result/module.min.js
@@ -0,0 +1 @@
+!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.simpleResult=a()}}(function(){var a;return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'" [...]
\ No newline at end of file
diff --git a/webcore/test/simple-result/package.json b/webcore/test/simple-result/package.json
new file mode 100644
index 0000000..232d28a
--- /dev/null
+++ b/webcore/test/simple-result/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "simple-result",
+  "version": "0.0.1",
+  "description": "A simple result table view for Dicoogle",
+  "scripts": {
+    "build": "grunt",
+    "build-debug": "grunt debug"
+  },
+  "dicoogle": {
+    "caption": "Simple Result",
+    "slot-id": "result",
+    "module-file": "module.js"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "grunt": "^0.4.5",
+    "grunt-browserify": "^3.7.0",
+    "grunt-contrib-clean": "^0.6.0",
+    "grunt-contrib-concat": "^0.5.1",
+    "grunt-contrib-jshint": "^0.11.2",
+    "grunt-contrib-jshint-jsx": "^0.10.2",
+    "grunt-contrib-uglify": "^0.9.1",
+    "grunt-react": "^0.12.1",
+    "grunt-umd": "^2.3.3",
+    "react-tools": "^0.13.1",
+    "reactable": "^0.10.1",
+    "reactify": "^1.1.0"
+  } 
+}
diff --git a/webcore/test/simple-result/simple-result.jsx b/webcore/test/simple-result/simple-result.jsx
new file mode 100644
index 0000000..427f002
--- /dev/null
+++ b/webcore/test/simple-result/simple-result.jsx
@@ -0,0 +1,80 @@
+// simple-result.jsx - Simple Result Module file (React JSX)
+
+// JSHint directives
+/* global require: false */
+/* global document: false */
+/* global console: false */
+/* global module: false */
+
+// external dependencies
+var React = require('react');
+
+// bundled dependencies
+var Reactable = require('reactable');
+
+var ResultTable = React.createClass({
+  getInitialState: function() {
+    return {
+      results : [],
+      resultNum: null,
+      requestTime: 0
+    };
+  },
+  onChange: function(e) {
+    //this.setState({text: e.target.value});
+  },
+  shouldComponentUpdate: function(nextProps, nextState) {
+    return nextProps.id !== this.props.id ||
+      (nextState.requestTime - this.state.requestTime) > 0;
+  },
+  componentWillUpdate: function(nextProps, nextState) {
+  },
+  render: function() {
+    var Table = Reactable.Table;
+    return (
+        <div>
+        <Table className="table" data={this.state.results} itemsPerPage={10} />
+      </div>
+    );
+  }
+});
+
+module.exports = function() {
+    var resultTable;
+    var handler;
+    this.render = function(parent) {
+      resultTable = <ResultTable />;
+      handler = React.render(resultTable, parent);
+    };
+    this.onResult = function(data, requestTime, options) {
+      if (!handler) {
+        console.error("onResult was invoked before the result plugin was rendered, ignoring");
+        return;
+      }
+      console.log('[onResult] Got ', data.numResults, ' entries.');
+      if (data.numResults === 0) {
+        handler.setState({
+          results: {},
+          n: 0,
+          elapsedTime: data.elapsedTime,
+          requestTime: requestTime,
+          });
+          return;
+      }
+      for (var i = 0 ; i < data.results.length ; i++) {
+        var fields = data.results[i].fields;
+        if (fields) {
+          delete data.results[i].fields;
+          for (var fname in fields) {
+            data.results[i][fname] = fields[fname];
+          }
+        }
+      }
+      handler.setState({
+        results: data.results,
+        n: data.numResults,
+        elapsedTime: data.elapsedTime,
+        requestTime: requestTime,
+      });
+    };
+};
diff --git a/webcore/test/simple-result/template/returnModuleExports.hbs b/webcore/test/simple-result/template/returnModuleExports.hbs
new file mode 100644
index 0000000..0c14179
--- /dev/null
+++ b/webcore/test/simple-result/template/returnModuleExports.hbs
@@ -0,0 +1,18 @@
+{{! UMD template that can be useful to wrap standalone CommonJS/Node modules}}
+(function(root, factory) {
+    if(typeof exports === 'object') {
+        module.exports = factory({{#if cjsDependencies.wrapped}}{{{cjsDependencies.wrapped}}}, {{/if}}require, exports, module);
+    }
+    else if(typeof define === 'function' && define.amd) {
+        define({{#if amdModuleId}}'{{amdModuleId}}', {{/if}}['require','exports','module',{{#if amdDependencies.wrapped}}{{{amdDependencies.wrapped}}}{{/if}}], factory);
+    }
+    else {
+        var req = function(id) {return root[id];},
+            exp = root,
+            mod = {exports: exp};
+        {{#if globalAlias}}root['{{globalAlias}}'] = {{else}}{{#if objectToExport}}root['{{objectToExport}}'] = {{/if}}{{/if}}factory({{#if globalDependencies.normal}}{{{globalDependencies.normal}}}, {{/if}}req, exp, mod);
+    }
+}(this, function({{#if dependencies}}{{dependencies}}, {{/if}}require, exports, module) {
+{{{code}}}
+return {{#if objectToExport}}{{objectToExport}}{{else}}module.exports{{/if}};
+}));

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/dicoogle.git



More information about the debian-med-commit mailing list