Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / PithosMonitor.cs @ 62d5b25f

History | View | Annotate | Download (21.2 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="PithosMonitor.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 d78cbf09 Panagiotis Kanavos
using System;
43 d78cbf09 Panagiotis Kanavos
using System.Collections.Concurrent;
44 d78cbf09 Panagiotis Kanavos
using System.Collections.Generic;
45 d78cbf09 Panagiotis Kanavos
using System.ComponentModel.Composition;
46 d78cbf09 Panagiotis Kanavos
using System.Diagnostics;
47 d78cbf09 Panagiotis Kanavos
using System.Diagnostics.Contracts;
48 d78cbf09 Panagiotis Kanavos
using System.IO;
49 d78cbf09 Panagiotis Kanavos
using System.Linq;
50 65282d58 Panagiotis Kanavos
using System.Net;
51 29672672 Panagiotis Kanavos
using System.Net.NetworkInformation;
52 d78cbf09 Panagiotis Kanavos
using System.Security.Cryptography;
53 5bcf6d70 Panagiotis Kanavos
using System.ServiceModel.Description;
54 d78cbf09 Panagiotis Kanavos
using System.Text;
55 d78cbf09 Panagiotis Kanavos
using System.Threading;
56 d78cbf09 Panagiotis Kanavos
using System.Threading.Tasks;
57 0eea575a Panagiotis Kanavos
using Castle.ActiveRecord.Queries;
58 637bc368 Panagiotis Kanavos
using Microsoft.WindowsAPICodePack.Net;
59 9c4346c9 Panagiotis Kanavos
using Pithos.Core.Agents;
60 d78cbf09 Panagiotis Kanavos
using Pithos.Interfaces;
61 eeee29e3 Panagiotis Kanavos
using System.ServiceModel;
62 5ce54458 Panagiotis Kanavos
using Pithos.Network;
63 5120f3cb Panagiotis Kanavos
using log4net;
64 d78cbf09 Panagiotis Kanavos
65 d78cbf09 Panagiotis Kanavos
namespace Pithos.Core
66 d78cbf09 Panagiotis Kanavos
{
67 d78cbf09 Panagiotis Kanavos
    [Export(typeof(PithosMonitor))]
68 d78cbf09 Panagiotis Kanavos
    public class PithosMonitor:IDisposable
69 d78cbf09 Panagiotis Kanavos
    {
70 5ce54458 Panagiotis Kanavos
        private int _blockSize;
71 5ce54458 Panagiotis Kanavos
        private string _blockHash;
72 5ce54458 Panagiotis Kanavos
73 d78cbf09 Panagiotis Kanavos
        [Import]
74 d78cbf09 Panagiotis Kanavos
        public IPithosSettings Settings{get;set;}
75 d78cbf09 Panagiotis Kanavos
76 4ec636f6 Panagiotis Kanavos
        private IStatusKeeper _statusKeeper;
77 4ec636f6 Panagiotis Kanavos
78 d78cbf09 Panagiotis Kanavos
        [Import]
79 4ec636f6 Panagiotis Kanavos
        public IStatusKeeper StatusKeeper
80 4ec636f6 Panagiotis Kanavos
        {
81 4ec636f6 Panagiotis Kanavos
            get { return _statusKeeper; }
82 4ec636f6 Panagiotis Kanavos
            set
83 4ec636f6 Panagiotis Kanavos
            {
84 4ec636f6 Panagiotis Kanavos
                _statusKeeper = value;
85 4ec636f6 Panagiotis Kanavos
                FileAgent.StatusKeeper = value;
86 4ec636f6 Panagiotis Kanavos
            }
87 4ec636f6 Panagiotis Kanavos
        }
88 4ec636f6 Panagiotis Kanavos
89 4ec636f6 Panagiotis Kanavos
90 4ec636f6 Panagiotis Kanavos
        private IPithosWorkflow _workflow;
91 d78cbf09 Panagiotis Kanavos
92 d78cbf09 Panagiotis Kanavos
        [Import]
93 4ec636f6 Panagiotis Kanavos
        public IPithosWorkflow Workflow
94 4ec636f6 Panagiotis Kanavos
        {
95 4ec636f6 Panagiotis Kanavos
            get { return _workflow; }
96 4ec636f6 Panagiotis Kanavos
            set
97 4ec636f6 Panagiotis Kanavos
            {
98 4ec636f6 Panagiotis Kanavos
                _workflow = value;
99 4ec636f6 Panagiotis Kanavos
                FileAgent.Workflow = value;
100 4ec636f6 Panagiotis Kanavos
            }
101 4ec636f6 Panagiotis Kanavos
        }
102 d78cbf09 Panagiotis Kanavos
103 d78cbf09 Panagiotis Kanavos
        public ICloudClient CloudClient { get; set; }
104 d78cbf09 Panagiotis Kanavos
105 0c02aa65 Panagiotis Kanavos
        public IStatusNotification StatusNotification { get; set; }
106 0c02aa65 Panagiotis Kanavos
107 4ec636f6 Panagiotis Kanavos
        //[Import]
108 4ec636f6 Panagiotis Kanavos
        public FileAgent FileAgent { get; private set; }
109 4ec636f6 Panagiotis Kanavos
110 4ec636f6 Panagiotis Kanavos
        private WorkflowAgent _workflowAgent;
111 4ec636f6 Panagiotis Kanavos
112 9c4346c9 Panagiotis Kanavos
        [Import]
113 4ec636f6 Panagiotis Kanavos
        public WorkflowAgent WorkflowAgent
114 4ec636f6 Panagiotis Kanavos
        {
115 4ec636f6 Panagiotis Kanavos
            get { return _workflowAgent; }
116 4ec636f6 Panagiotis Kanavos
            set
117 4ec636f6 Panagiotis Kanavos
            {
118 4ec636f6 Panagiotis Kanavos
                _workflowAgent = value;
119 4ec636f6 Panagiotis Kanavos
                FileAgent.WorkflowAgent = value;
120 4ec636f6 Panagiotis Kanavos
            }
121 4ec636f6 Panagiotis Kanavos
        }
122 9c4346c9 Panagiotis Kanavos
        
123 9c4346c9 Panagiotis Kanavos
        [Import]
124 aa7ac00e Panagiotis Kanavos
        public NetworkAgent NetworkAgent { get; set; }
125 aa7ac00e Panagiotis Kanavos
        [Import]
126 aa7ac00e Panagiotis Kanavos
        public PollAgent PollAgent { get; set; }       
127 9c4346c9 Panagiotis Kanavos
128 0eea575a Panagiotis Kanavos
        public string UserName { get; set; }
129 c92e02f3 Panagiotis Kanavos
        private string _apiKey;
130 c92e02f3 Panagiotis Kanavos
        public string ApiKey
131 c92e02f3 Panagiotis Kanavos
        {
132 c92e02f3 Panagiotis Kanavos
            get { return _apiKey; }
133 c92e02f3 Panagiotis Kanavos
            set
134 c92e02f3 Panagiotis Kanavos
            {
135 c92e02f3 Panagiotis Kanavos
                _apiKey = value;
136 c92e02f3 Panagiotis Kanavos
                if (_accountInfo != null)
137 c92e02f3 Panagiotis Kanavos
                    _accountInfo.Token = value;
138 c92e02f3 Panagiotis Kanavos
            }
139 c92e02f3 Panagiotis Kanavos
        }
140 0eea575a Panagiotis Kanavos
141 0bd56b7c Panagiotis Kanavos
        private AccountInfo _accountInfo;
142 4ec636f6 Panagiotis Kanavos
        
143 4ec636f6 Panagiotis Kanavos
       
144 c53aa229 Panagiotis Kanavos
145 eeee29e3 Panagiotis Kanavos
146 5120f3cb Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger(typeof(PithosMonitor));
147 5120f3cb Panagiotis Kanavos
148 d78cbf09 Panagiotis Kanavos
149 d78cbf09 Panagiotis Kanavos
        public bool Pause
150 d78cbf09 Panagiotis Kanavos
        {
151 5ce54458 Panagiotis Kanavos
            get { return FileAgent.Pause; }
152 d78cbf09 Panagiotis Kanavos
            set
153 d78cbf09 Panagiotis Kanavos
            {
154 5ce54458 Panagiotis Kanavos
                FileAgent.Pause = value;
155 5bcf6d70 Panagiotis Kanavos
                if (value)
156 5bcf6d70 Panagiotis Kanavos
                {
157 5bcf6d70 Panagiotis Kanavos
                    StatusKeeper.SetPithosStatus(PithosStatus.SyncPaused);
158 0c02aa65 Panagiotis Kanavos
                    StatusNotification.NotifyChange("Paused");
159 5bcf6d70 Panagiotis Kanavos
                }
160 5bcf6d70 Panagiotis Kanavos
                else
161 5bcf6d70 Panagiotis Kanavos
                {
162 5bcf6d70 Panagiotis Kanavos
                    StatusKeeper.SetPithosStatus(PithosStatus.InSynch);
163 9c4346c9 Panagiotis Kanavos
                    StatusNotification.NotifyChange("Synchronizing");
164 5bcf6d70 Panagiotis Kanavos
                }
165 d78cbf09 Panagiotis Kanavos
            }
166 d78cbf09 Panagiotis Kanavos
        }
167 d78cbf09 Panagiotis Kanavos
168 c28a075a Panagiotis Kanavos
        private string _rootPath;
169 c28a075a Panagiotis Kanavos
        public string RootPath
170 c28a075a Panagiotis Kanavos
        {
171 c28a075a Panagiotis Kanavos
            get { return _rootPath; }
172 7e26c075 Panagiotis Kanavos
            set 
173 c28a075a Panagiotis Kanavos
            {
174 7e26c075 Panagiotis Kanavos
                _rootPath = String.IsNullOrWhiteSpace(value) 
175 7e26c075 Panagiotis Kanavos
                    ? String.Empty 
176 7e26c075 Panagiotis Kanavos
                    : value.ToLower();
177 c28a075a Panagiotis Kanavos
            }
178 c28a075a Panagiotis Kanavos
        }
179 0eea575a Panagiotis Kanavos
180 d78cbf09 Panagiotis Kanavos
181 d78cbf09 Panagiotis Kanavos
        CancellationTokenSource _cancellationSource;
182 d78cbf09 Panagiotis Kanavos
183 4ec636f6 Panagiotis Kanavos
        public PithosMonitor()
184 4ec636f6 Panagiotis Kanavos
        {
185 4ec636f6 Panagiotis Kanavos
            FileAgent = new FileAgent();
186 d78cbf09 Panagiotis Kanavos
187 4ec636f6 Panagiotis Kanavos
        }
188 7e26c075 Panagiotis Kanavos
        private bool _started;
189 d78cbf09 Panagiotis Kanavos
190 d78cbf09 Panagiotis Kanavos
        public void Start()
191 c53aa229 Panagiotis Kanavos
        {            
192 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(ApiKey))
193 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("The ApiKey is empty");
194 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(UserName))
195 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("The UserName is empty");
196 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(AuthenticationUrl))
197 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("The Authentication url is empty");
198 c53aa229 Panagiotis Kanavos
            Contract.EndContractBlock();
199 c53aa229 Panagiotis Kanavos
200 437abfca Panagiotis Kanavos
            //If the account doesn't have a valid path, don't start monitoring but don't throw either
201 437abfca Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(RootPath))
202 437abfca Panagiotis Kanavos
                //TODO; Warn user?
203 437abfca Panagiotis Kanavos
                return;
204 437abfca Panagiotis Kanavos
205 70f12b36 Panagiotis Kanavos
            WorkflowAgent.StatusNotification = StatusNotification;
206 70f12b36 Panagiotis Kanavos
207 0c02aa65 Panagiotis Kanavos
            StatusNotification.NotifyChange("Starting");
208 7e26c075 Panagiotis Kanavos
            if (_started)
209 d78cbf09 Panagiotis Kanavos
            {
210 d78cbf09 Panagiotis Kanavos
                if (!_cancellationSource.IsCancellationRequested)
211 d78cbf09 Panagiotis Kanavos
                    return;
212 d78cbf09 Panagiotis Kanavos
            }
213 29672672 Panagiotis Kanavos
            _cancellationSource = new CancellationTokenSource();
214 c92e02f3 Panagiotis Kanavos
            
215 d78cbf09 Panagiotis Kanavos
216 c53aa229 Panagiotis Kanavos
            CloudClient=new CloudFilesClient(UserName,ApiKey);
217 74d78c90 Panagiotis Kanavos
            CloudClient.UsePithos = true;
218 c53aa229 Panagiotis Kanavos
            CloudClient.AuthenticationUrl = this.AuthenticationUrl;            
219 c53aa229 Panagiotis Kanavos
220 23821bd2 Panagiotis Kanavos
            _accountInfo = CloudClient.Authenticate();            
221 23821bd2 Panagiotis Kanavos
            _accountInfo.SiteUri = AuthenticationUrl;
222 c53aa229 Panagiotis Kanavos
            _accountInfo.AccountPath = RootPath;
223 c53aa229 Panagiotis Kanavos
224 5750d7cc Panagiotis Kanavos
225 5750d7cc Panagiotis Kanavos
            var pithosFolder = Path.Combine(RootPath, FolderConstants.PithosContainer);
226 5750d7cc Panagiotis Kanavos
            if (!Directory.Exists(pithosFolder))
227 5750d7cc Panagiotis Kanavos
                Directory.CreateDirectory(pithosFolder);
228 77e10b4f Panagiotis Kanavos
            //Create the cache folder and ensure it is hidden
229 77e10b4f Panagiotis Kanavos
            CreateHiddenFolder(RootPath, FolderConstants.CacheFolder);
230 77e10b4f Panagiotis Kanavos
231 0bd56b7c Panagiotis Kanavos
            var policy=CloudClient.GetAccountPolicies(_accountInfo);
232 c53aa229 Panagiotis Kanavos
233 0bd56b7c Panagiotis Kanavos
            StatusNotification.NotifyAccount(policy);
234 3c43ec9b Panagiotis Kanavos
            EnsurePithosContainers();
235 9c4346c9 Panagiotis Kanavos
            
236 5ce54458 Panagiotis Kanavos
            StatusKeeper.BlockHash = _blockHash;
237 5ce54458 Panagiotis Kanavos
            StatusKeeper.BlockSize = _blockSize;
238 9c4346c9 Panagiotis Kanavos
            
239 3c43ec9b Panagiotis Kanavos
            StatusKeeper.StartProcessing(_cancellationSource.Token);
240 c28a075a Panagiotis Kanavos
            IndexLocalFiles();
241 759bd3c4 Panagiotis Kanavos
            //Extract the URIs from the string collection
242 759bd3c4 Panagiotis Kanavos
            var settings = Settings.Accounts.First(s => s.AccountName == _accountInfo.UserName);
243 fec5da06 Panagiotis Kanavos
            var selectiveUrls=settings.SelectiveFolders.Cast<string>().Select(url => new Uri(url)).ToArray();
244 759bd3c4 Panagiotis Kanavos
245 759bd3c4 Panagiotis Kanavos
            SetSelectivePaths(selectiveUrls,null,null);
246 759bd3c4 Panagiotis Kanavos
            
247 c28a075a Panagiotis Kanavos
            StartWatcherAgent();
248 c53aa229 Panagiotis Kanavos
249 c53aa229 Panagiotis Kanavos
            StartNetworkAgent();
250 70f12b36 Panagiotis Kanavos
            
251 c92e02f3 Panagiotis Kanavos
            WorkflowAgent.RestartInterruptedFiles(_accountInfo);
252 c92e02f3 Panagiotis Kanavos
            _started = true;
253 29672672 Panagiotis Kanavos
        }
254 29672672 Panagiotis Kanavos
255 3c43ec9b Panagiotis Kanavos
        private void EnsurePithosContainers()
256 3c43ec9b Panagiotis Kanavos
        {
257 3c43ec9b Panagiotis Kanavos
258 cfed7823 Panagiotis Kanavos
            //Create the two default containers if they are missing
259 c53aa229 Panagiotis Kanavos
            var pithosContainers = new List<string>{ FolderConstants.TrashContainer,FolderConstants.PithosContainer};
260 3c43ec9b Panagiotis Kanavos
            foreach (var container in pithosContainers)
261 cfed7823 Panagiotis Kanavos
            {                
262 cfed7823 Panagiotis Kanavos
                var info=CloudClient.GetContainerInfo(this.UserName, container);
263 5ce54458 Panagiotis Kanavos
                if (info == ContainerInfo.Empty)
264 5ce54458 Panagiotis Kanavos
                {
265 cfed7823 Panagiotis Kanavos
                    CloudClient.CreateContainer(this.UserName, container);
266 cfed7823 Panagiotis Kanavos
                    info = CloudClient.GetContainerInfo(this.UserName, container);
267 5ce54458 Panagiotis Kanavos
                }
268 5ce54458 Panagiotis Kanavos
                _blockSize = info.BlockSize;
269 5ce54458 Panagiotis Kanavos
                _blockHash = info.BlockHash;
270 c53aa229 Panagiotis Kanavos
                _accountInfo.BlockSize = _blockSize;
271 c53aa229 Panagiotis Kanavos
                _accountInfo.BlockHash = _blockHash;
272 3c43ec9b Panagiotis Kanavos
            }
273 3c43ec9b Panagiotis Kanavos
        }
274 3c43ec9b Panagiotis Kanavos
275 79736291 Panagiotis Kanavos
        public string AuthenticationUrl { get; set; }
276 79736291 Panagiotis Kanavos
277 c28a075a Panagiotis Kanavos
        private void IndexLocalFiles()
278 b5061ac8 Panagiotis Kanavos
        {
279 0c02aa65 Panagiotis Kanavos
            StatusNotification.NotifyChange("Indexing Local Files",TraceLevel.Info);
280 5120f3cb Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["Monitor"].Push("Indexing local files"))
281 b5061ac8 Panagiotis Kanavos
            {
282 5120f3cb Panagiotis Kanavos
                Log.Info("START");
283 5120f3cb Panagiotis Kanavos
                try
284 5120f3cb Panagiotis Kanavos
                {
285 77e10b4f Panagiotis Kanavos
                    var cachePath = Path.Combine(RootPath, FolderConstants.CacheFolder);
286 c28a075a Panagiotis Kanavos
                    var directory = new DirectoryInfo(RootPath);
287 5120f3cb Panagiotis Kanavos
                    var files =
288 5120f3cb Panagiotis Kanavos
                        from file in directory.EnumerateFiles("*", SearchOption.AllDirectories)
289 77e10b4f Panagiotis Kanavos
                        where !file.FullName.StartsWith(cachePath, StringComparison.InvariantCultureIgnoreCase) &&
290 5120f3cb Panagiotis Kanavos
                              !file.Extension.Equals("ignore", StringComparison.InvariantCultureIgnoreCase)
291 5120f3cb Panagiotis Kanavos
                        select file;
292 5120f3cb Panagiotis Kanavos
                    StatusKeeper.ProcessExistingFiles(files);
293 5120f3cb Panagiotis Kanavos
294 5120f3cb Panagiotis Kanavos
                }
295 5120f3cb Panagiotis Kanavos
                catch (Exception exc)
296 5120f3cb Panagiotis Kanavos
                {
297 5120f3cb Panagiotis Kanavos
                    Log.Error("[ERROR]", exc);
298 5120f3cb Panagiotis Kanavos
                }
299 5120f3cb Panagiotis Kanavos
                finally
300 5120f3cb Panagiotis Kanavos
                {
301 5120f3cb Panagiotis Kanavos
                    Log.Info("[END]");
302 5120f3cb Panagiotis Kanavos
                }
303 b5061ac8 Panagiotis Kanavos
            }
304 b5061ac8 Panagiotis Kanavos
        }
305 b5061ac8 Panagiotis Kanavos
306 9c4346c9 Panagiotis Kanavos
        
307 c53aa229 Panagiotis Kanavos
  
308 eeee29e3 Panagiotis Kanavos
309 eeee29e3 Panagiotis Kanavos
310 70f12b36 Panagiotis Kanavos
       /* private void StartWorkflowAgent()
311 29672672 Panagiotis Kanavos
        {
312 65282d58 Panagiotis Kanavos
            WorkflowAgent.StatusNotification = StatusNotification;
313 65282d58 Panagiotis Kanavos
314 65282d58 Panagiotis Kanavos
/*            //On Vista and up we can check for a network connection
315 56b53955 Panagiotis Kanavos
            bool connected=Environment.OSVersion.Version.Major < 6 || NetworkListManager.IsConnectedToInternet;
316 29672672 Panagiotis Kanavos
            //If we are not connected retry later
317 29672672 Panagiotis Kanavos
            if (!connected)
318 29672672 Panagiotis Kanavos
            {
319 9c4346c9 Panagiotis Kanavos
                Task.Factory.StartNewDelayed(10000, StartWorkflowAgent);
320 29672672 Panagiotis Kanavos
                return;
321 70f12b36 Panagiotis Kanavos
            }#1#
322 29672672 Panagiotis Kanavos
323 29672672 Panagiotis Kanavos
            try
324 29672672 Panagiotis Kanavos
            {
325 9c4346c9 Panagiotis Kanavos
                WorkflowAgent.Start();                
326 29672672 Panagiotis Kanavos
            }
327 29672672 Panagiotis Kanavos
            catch (Exception)
328 29672672 Panagiotis Kanavos
            {
329 29672672 Panagiotis Kanavos
                //Faild to authenticate due to network or account error
330 29672672 Panagiotis Kanavos
                //Retry after a while
331 9c4346c9 Panagiotis Kanavos
                Task.Factory.StartNewDelayed(10000, StartWorkflowAgent);
332 29672672 Panagiotis Kanavos
            }
333 70f12b36 Panagiotis Kanavos
        }*/
334 d78cbf09 Panagiotis Kanavos
335 9c4346c9 Panagiotis Kanavos
        internal class LocalFileComparer:EqualityComparer<CloudAction>
336 d78cbf09 Panagiotis Kanavos
        {
337 9c4346c9 Panagiotis Kanavos
            public override bool Equals(CloudAction x, CloudAction y)
338 d78cbf09 Panagiotis Kanavos
            {
339 d78cbf09 Panagiotis Kanavos
                if (x.Action != y.Action)
340 d78cbf09 Panagiotis Kanavos
                    return false;
341 d78cbf09 Panagiotis Kanavos
                if (x.LocalFile != null && y.LocalFile != null && !x.LocalFile.FullName.Equals(y.LocalFile.FullName))
342 d78cbf09 Panagiotis Kanavos
                    return false;
343 0af3141d Panagiotis Kanavos
                if (x.CloudFile != null && y.CloudFile != null )
344 0af3141d Panagiotis Kanavos
                {
345 0af3141d Panagiotis Kanavos
                    if (x.CloudFile.Hash == null & y.CloudFile.Hash != null)
346 0af3141d Panagiotis Kanavos
                        return false;
347 0af3141d Panagiotis Kanavos
                    if (x.CloudFile.Hash != null & y.CloudFile.Hash == null)
348 0af3141d Panagiotis Kanavos
                        return false;
349 0af3141d Panagiotis Kanavos
                    if (x.CloudFile.Hash == null & y.CloudFile.Hash == null)
350 0af3141d Panagiotis Kanavos
                        return (x.CloudFile.Name == y.CloudFile.Name);
351 0af3141d Panagiotis Kanavos
                    if (!x.CloudFile.Hash.Equals(y.CloudFile.Hash))
352 0af3141d Panagiotis Kanavos
                        return false;
353 0af3141d Panagiotis Kanavos
                }
354 d78cbf09 Panagiotis Kanavos
                if (x.CloudFile == null ^ y.CloudFile == null ||
355 d78cbf09 Panagiotis Kanavos
                    x.LocalFile == null ^ y.LocalFile == null)
356 d78cbf09 Panagiotis Kanavos
                    return false;
357 d78cbf09 Panagiotis Kanavos
                return true;
358 d78cbf09 Panagiotis Kanavos
            }
359 d78cbf09 Panagiotis Kanavos
360 9c4346c9 Panagiotis Kanavos
            public override int GetHashCode(CloudAction obj)
361 d78cbf09 Panagiotis Kanavos
            {
362 d78cbf09 Panagiotis Kanavos
                var hash1 = (obj.LocalFile == null) ? int.MaxValue : obj.LocalFile.FullName.GetHashCode();
363 cfed7823 Panagiotis Kanavos
                var hash2 = (obj.CloudFile == null) ? int.MaxValue : (obj.CloudFile.Hash ?? obj.CloudFile.Name??"").GetHashCode();
364 d78cbf09 Panagiotis Kanavos
                var hash3 = obj.Action.GetHashCode();
365 d78cbf09 Panagiotis Kanavos
                return hash1 ^ hash2 & hash3;
366 d78cbf09 Panagiotis Kanavos
            }
367 9c4346c9 Panagiotis Kanavos
        }        
368 d78cbf09 Panagiotis Kanavos
369 d78cbf09 Panagiotis Kanavos
        private Timer timer;
370 d78cbf09 Panagiotis Kanavos
371 c53aa229 Panagiotis Kanavos
        private void StartNetworkAgent()
372 d78cbf09 Panagiotis Kanavos
        {
373 c53aa229 Panagiotis Kanavos
374 c53aa229 Panagiotis Kanavos
            NetworkAgent.AddAccount(_accountInfo);
375 c53aa229 Panagiotis Kanavos
376 9c4346c9 Panagiotis Kanavos
            NetworkAgent.StatusNotification = StatusNotification;
377 c28a075a Panagiotis Kanavos
                        
378 c53aa229 Panagiotis Kanavos
            NetworkAgent.Start();
379 d78cbf09 Panagiotis Kanavos
380 fec5da06 Panagiotis Kanavos
            PollAgent.AddAccount(_accountInfo);
381 fec5da06 Panagiotis Kanavos
382 aa7ac00e Panagiotis Kanavos
            PollAgent.StatusNotification = StatusNotification;
383 aa7ac00e Panagiotis Kanavos
384 aa7ac00e Panagiotis Kanavos
            PollAgent.PollRemoteFiles();
385 d78cbf09 Panagiotis Kanavos
        }
386 d78cbf09 Panagiotis Kanavos
387 77e10b4f Panagiotis Kanavos
        //Make sure a hidden cache folder exists to store partial downloads
388 5ce54458 Panagiotis Kanavos
        private static string CreateHiddenFolder(string rootPath, string folderName)
389 5ce54458 Panagiotis Kanavos
        {
390 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(rootPath))
391 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("rootPath");
392 5ce54458 Panagiotis Kanavos
            if (!Path.IsPathRooted(rootPath))
393 5ce54458 Panagiotis Kanavos
                throw new ArgumentException("rootPath");
394 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(folderName))
395 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("folderName");
396 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
397 5ce54458 Panagiotis Kanavos
398 5ce54458 Panagiotis Kanavos
            var folder = Path.Combine(rootPath, folderName);
399 5ce54458 Panagiotis Kanavos
            if (!Directory.Exists(folder))
400 5ce54458 Panagiotis Kanavos
            {
401 5ce54458 Panagiotis Kanavos
                var info = Directory.CreateDirectory(folder);
402 5ce54458 Panagiotis Kanavos
                info.Attributes |= FileAttributes.Hidden;
403 5ce54458 Panagiotis Kanavos
404 77e10b4f Panagiotis Kanavos
                Log.InfoFormat("Created cache Folder: {0}", folder);
405 77e10b4f Panagiotis Kanavos
            }
406 77e10b4f Panagiotis Kanavos
            else
407 77e10b4f Panagiotis Kanavos
            {
408 77e10b4f Panagiotis Kanavos
                var info = new DirectoryInfo(folder);
409 77e10b4f Panagiotis Kanavos
                if ((info.Attributes & FileAttributes.Hidden) == 0)
410 77e10b4f Panagiotis Kanavos
                {
411 77e10b4f Panagiotis Kanavos
                    info.Attributes |= FileAttributes.Hidden;
412 77e10b4f Panagiotis Kanavos
                    Log.InfoFormat("Reset cache folder to hidden: {0}", folder);
413 77e10b4f Panagiotis Kanavos
                }                                
414 5ce54458 Panagiotis Kanavos
            }
415 5ce54458 Panagiotis Kanavos
            return folder;
416 5ce54458 Panagiotis Kanavos
        }
417 5ce54458 Panagiotis Kanavos
418 b5061ac8 Panagiotis Kanavos
       
419 d78cbf09 Panagiotis Kanavos
420 d78cbf09 Panagiotis Kanavos
421 c28a075a Panagiotis Kanavos
        private void StartWatcherAgent()
422 d78cbf09 Panagiotis Kanavos
        {
423 c28a075a Panagiotis Kanavos
            AgentLocator<FileAgent>.Register(FileAgent,RootPath);
424 c28a075a Panagiotis Kanavos
425 5ce54458 Panagiotis Kanavos
            FileAgent.StatusKeeper = StatusKeeper;
426 5ce54458 Panagiotis Kanavos
            FileAgent.Workflow = Workflow;
427 77e10b4f Panagiotis Kanavos
            FileAgent.CachePath = Path.Combine(RootPath, FolderConstants.CacheFolder);
428 c28a075a Panagiotis Kanavos
            FileAgent.Start(_accountInfo, RootPath);
429 d78cbf09 Panagiotis Kanavos
        }
430 d78cbf09 Panagiotis Kanavos
431 d78cbf09 Panagiotis Kanavos
        public void Stop()
432 c28a075a Panagiotis Kanavos
        {
433 c28a075a Panagiotis Kanavos
            AgentLocator<FileAgent>.Remove(RootPath);
434 c28a075a Panagiotis Kanavos
435 c53aa229 Panagiotis Kanavos
            if (FileAgent!=null)
436 c53aa229 Panagiotis Kanavos
                FileAgent.Stop();
437 c53aa229 Panagiotis Kanavos
            FileAgent = null;
438 d78cbf09 Panagiotis Kanavos
            if (timer != null)
439 d78cbf09 Panagiotis Kanavos
                timer.Dispose();
440 c53aa229 Panagiotis Kanavos
            timer = null;            
441 d78cbf09 Panagiotis Kanavos
        }
442 d78cbf09 Panagiotis Kanavos
443 eeee29e3 Panagiotis Kanavos
444 d78cbf09 Panagiotis Kanavos
        ~PithosMonitor()
445 d78cbf09 Panagiotis Kanavos
        {
446 d78cbf09 Panagiotis Kanavos
            Dispose(false);
447 d78cbf09 Panagiotis Kanavos
        }
448 d78cbf09 Panagiotis Kanavos
449 d78cbf09 Panagiotis Kanavos
        public void Dispose()
450 d78cbf09 Panagiotis Kanavos
        {
451 d78cbf09 Panagiotis Kanavos
            Dispose(true);
452 d78cbf09 Panagiotis Kanavos
            GC.SuppressFinalize(this);
453 d78cbf09 Panagiotis Kanavos
        }
454 d78cbf09 Panagiotis Kanavos
455 d78cbf09 Panagiotis Kanavos
        protected virtual void Dispose(bool disposing)
456 d78cbf09 Panagiotis Kanavos
        {
457 d78cbf09 Panagiotis Kanavos
            if (disposing)
458 d78cbf09 Panagiotis Kanavos
            {
459 d78cbf09 Panagiotis Kanavos
                Stop();
460 d78cbf09 Panagiotis Kanavos
            }
461 d78cbf09 Panagiotis Kanavos
        }
462 d78cbf09 Panagiotis Kanavos
463 d78cbf09 Panagiotis Kanavos
464 5120f3cb Panagiotis Kanavos
        public void MoveFileStates(string oldPath, string newPath)
465 5120f3cb Panagiotis Kanavos
        {
466 5120f3cb Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(oldPath))
467 5120f3cb Panagiotis Kanavos
                throw new ArgumentNullException("oldPath");
468 5120f3cb Panagiotis Kanavos
            if (!Path.IsPathRooted(oldPath))
469 5120f3cb Panagiotis Kanavos
                throw new ArgumentException("oldPath must be an absolute path","oldPath");
470 5120f3cb Panagiotis Kanavos
            if (string.IsNullOrWhiteSpace(newPath))
471 5120f3cb Panagiotis Kanavos
                throw new ArgumentNullException("newPath");
472 5120f3cb Panagiotis Kanavos
            if (!Path.IsPathRooted(newPath))
473 5120f3cb Panagiotis Kanavos
                throw new ArgumentException("newPath must be an absolute path","newPath");
474 5120f3cb Panagiotis Kanavos
            Contract.EndContractBlock();
475 5120f3cb Panagiotis Kanavos
476 5120f3cb Panagiotis Kanavos
            StatusKeeper.ChangeRoots(oldPath, newPath);
477 5120f3cb Panagiotis Kanavos
        }
478 d3a13891 Panagiotis Kanavos
479 fec5da06 Panagiotis Kanavos
        public void SetSelectivePaths(Uri[] uris,Uri[] added, Uri[] removed)
480 d3a13891 Panagiotis Kanavos
        {
481 759bd3c4 Panagiotis Kanavos
            //Convert the uris to paths
482 fec5da06 Panagiotis Kanavos
            var selectivePaths = UrisToFilePaths(uris);
483 fec5da06 Panagiotis Kanavos
            
484 fec5da06 Panagiotis Kanavos
            FileAgent.SelectivePaths=selectivePaths;
485 759bd3c4 Panagiotis Kanavos
            PollAgent.SetSyncUris(uris);
486 759bd3c4 Panagiotis Kanavos
487 fec5da06 Panagiotis Kanavos
            var removedPaths = UrisToFilePaths(removed);
488 fec5da06 Panagiotis Kanavos
            RemoveSelectivePaths(removedPaths);
489 fec5da06 Panagiotis Kanavos
490 fec5da06 Panagiotis Kanavos
        }
491 fec5da06 Panagiotis Kanavos
492 fec5da06 Panagiotis Kanavos
        /// <summary>
493 fec5da06 Panagiotis Kanavos
        /// Return a list of absolute filepaths from a list of Uris
494 fec5da06 Panagiotis Kanavos
        /// </summary>
495 fec5da06 Panagiotis Kanavos
        /// <param name="uris"></param>
496 fec5da06 Panagiotis Kanavos
        /// <returns></returns>
497 fec5da06 Panagiotis Kanavos
        private List<string> UrisToFilePaths(IEnumerable<Uri> uris)
498 fec5da06 Panagiotis Kanavos
        {
499 fec5da06 Panagiotis Kanavos
            if (uris == null)
500 fec5da06 Panagiotis Kanavos
                return new List<string>();
501 fec5da06 Panagiotis Kanavos
502 fec5da06 Panagiotis Kanavos
            return (from uri in uris
503 fec5da06 Panagiotis Kanavos
                    let relativePath = _accountInfo.StorageUri
504 fec5da06 Panagiotis Kanavos
                        .MakeRelativeUri(uri)
505 fec5da06 Panagiotis Kanavos
                        .RelativeUriToFilePath()
506 62d5b25f Panagiotis Kanavos
                        //Trim the account name
507 62d5b25f Panagiotis Kanavos
                    select Path.Combine(RootPath, relativePath.After(_accountInfo.UserName + '\\'))).ToList();            
508 d3a13891 Panagiotis Kanavos
        }
509 d3a13891 Panagiotis Kanavos
510 759bd3c4 Panagiotis Kanavos
        /// <summary>
511 759bd3c4 Panagiotis Kanavos
        /// Delete the folders that were removed from synchronization
512 759bd3c4 Panagiotis Kanavos
        /// </summary>
513 759bd3c4 Panagiotis Kanavos
        /// <param name="removed"></param>
514 fec5da06 Panagiotis Kanavos
        private void RemoveSelectivePaths(List<string> removed)
515 d3a13891 Panagiotis Kanavos
        {
516 759bd3c4 Panagiotis Kanavos
            if (removed == null)
517 759bd3c4 Panagiotis Kanavos
                return;
518 759bd3c4 Panagiotis Kanavos
519 d3a13891 Panagiotis Kanavos
            foreach (var removedPath in removed.Where(Directory.Exists))
520 d3a13891 Panagiotis Kanavos
            {
521 62d5b25f Panagiotis Kanavos
                try
522 62d5b25f Panagiotis Kanavos
                {
523 62d5b25f Panagiotis Kanavos
                    Directory.Delete(removedPath, true);
524 62d5b25f Panagiotis Kanavos
                }
525 62d5b25f Panagiotis Kanavos
                catch { }
526 d3a13891 Panagiotis Kanavos
            }
527 7e26c075 Panagiotis Kanavos
528 759bd3c4 Panagiotis Kanavos
            //Ensure we remove any file state below the deleted folders
529 759bd3c4 Panagiotis Kanavos
            FileState.RemovePaths(removed);
530 7e26c075 Panagiotis Kanavos
        }
531 7b0a5fec Panagiotis Kanavos
532 7b0a5fec Panagiotis Kanavos
        public ObjectInfo GetObjectInfo(string filePath)
533 7b0a5fec Panagiotis Kanavos
        {
534 7b0a5fec Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(filePath))
535 7b0a5fec Panagiotis Kanavos
                throw new ArgumentNullException("filePath");
536 7b0a5fec Panagiotis Kanavos
            Contract.EndContractBlock();
537 7b0a5fec Panagiotis Kanavos
538 7b0a5fec Panagiotis Kanavos
            var file=new FileInfo(filePath);
539 7b0a5fec Panagiotis Kanavos
            string relativeUrl;//=file.AsRelativeUrlTo(this.RootPath);
540 7b0a5fec Panagiotis Kanavos
            var relativePath = file.AsRelativeTo(RootPath);
541 7b0a5fec Panagiotis Kanavos
            
542 7b0a5fec Panagiotis Kanavos
            string accountName,container;
543 7b0a5fec Panagiotis Kanavos
            
544 7b0a5fec Panagiotis Kanavos
            var parts=relativePath.Split('\\');
545 7b0a5fec Panagiotis Kanavos
546 7b0a5fec Panagiotis Kanavos
            var accountInfo = _accountInfo;
547 7b0a5fec Panagiotis Kanavos
            if (relativePath.StartsWith(FolderConstants.OthersFolder))
548 7b0a5fec Panagiotis Kanavos
            {                
549 7b0a5fec Panagiotis Kanavos
                accountName = parts[1];
550 7b0a5fec Panagiotis Kanavos
                container = parts[2];
551 7b0a5fec Panagiotis Kanavos
                relativeUrl = String.Join("/", parts.Splice(3));
552 7b0a5fec Panagiotis Kanavos
                //Create the root URL for the target account
553 7b0a5fec Panagiotis Kanavos
                var oldName = UserName;
554 7b0a5fec Panagiotis Kanavos
                var absoluteUri =  _accountInfo.StorageUri.AbsoluteUri;
555 7b0a5fec Panagiotis Kanavos
                var nameIndex=absoluteUri.IndexOf(oldName);
556 7b0a5fec Panagiotis Kanavos
                var root=absoluteUri.Substring(0, nameIndex);
557 7b0a5fec Panagiotis Kanavos
558 7b0a5fec Panagiotis Kanavos
                accountInfo = new AccountInfo
559 7b0a5fec Panagiotis Kanavos
                {
560 7b0a5fec Panagiotis Kanavos
                    UserName = accountName,
561 7b0a5fec Panagiotis Kanavos
                    AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]),
562 7b0a5fec Panagiotis Kanavos
                    StorageUri = new Uri(root + accountName),
563 7b0a5fec Panagiotis Kanavos
                    BlockHash=accountInfo.BlockHash,
564 7b0a5fec Panagiotis Kanavos
                    BlockSize=accountInfo.BlockSize,
565 7b0a5fec Panagiotis Kanavos
                    Token=accountInfo.Token
566 7b0a5fec Panagiotis Kanavos
                };
567 7b0a5fec Panagiotis Kanavos
            }
568 7b0a5fec Panagiotis Kanavos
            else
569 7b0a5fec Panagiotis Kanavos
            {
570 7b0a5fec Panagiotis Kanavos
                accountName = this.UserName;
571 7b0a5fec Panagiotis Kanavos
                container = parts[0];
572 7b0a5fec Panagiotis Kanavos
                relativeUrl = String.Join("/", parts.Splice(1));
573 7b0a5fec Panagiotis Kanavos
            }
574 42800be8 Panagiotis Kanavos
            
575 7b0a5fec Panagiotis Kanavos
            var client = new CloudFilesClient(accountInfo);
576 7b0a5fec Panagiotis Kanavos
            var objectInfo=client.GetObjectInfo(accountName, container, relativeUrl);
577 7b0a5fec Panagiotis Kanavos
            return objectInfo;
578 7b0a5fec Panagiotis Kanavos
        }
579 42800be8 Panagiotis Kanavos
        
580 c92e02f3 Panagiotis Kanavos
        public Task<ContainerInfo> GetContainerInfo(string filePath)
581 42800be8 Panagiotis Kanavos
        {
582 42800be8 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(filePath))
583 42800be8 Panagiotis Kanavos
                throw new ArgumentNullException("filePath");
584 42800be8 Panagiotis Kanavos
            Contract.EndContractBlock();
585 42800be8 Panagiotis Kanavos
586 42800be8 Panagiotis Kanavos
            var file=new FileInfo(filePath);
587 42800be8 Panagiotis Kanavos
            var relativePath = file.AsRelativeTo(RootPath);
588 42800be8 Panagiotis Kanavos
            
589 42800be8 Panagiotis Kanavos
            string accountName,container;
590 42800be8 Panagiotis Kanavos
            
591 42800be8 Panagiotis Kanavos
            var parts=relativePath.Split('\\');
592 42800be8 Panagiotis Kanavos
593 42800be8 Panagiotis Kanavos
            var accountInfo = _accountInfo;
594 42800be8 Panagiotis Kanavos
            if (relativePath.StartsWith(FolderConstants.OthersFolder))
595 42800be8 Panagiotis Kanavos
            {                
596 42800be8 Panagiotis Kanavos
                accountName = parts[1];
597 42800be8 Panagiotis Kanavos
                container = parts[2];                
598 42800be8 Panagiotis Kanavos
                //Create the root URL for the target account
599 42800be8 Panagiotis Kanavos
                var oldName = UserName;
600 42800be8 Panagiotis Kanavos
                var absoluteUri =  _accountInfo.StorageUri.AbsoluteUri;
601 42800be8 Panagiotis Kanavos
                var nameIndex=absoluteUri.IndexOf(oldName);
602 42800be8 Panagiotis Kanavos
                var root=absoluteUri.Substring(0, nameIndex);
603 42800be8 Panagiotis Kanavos
604 42800be8 Panagiotis Kanavos
                accountInfo = new AccountInfo
605 42800be8 Panagiotis Kanavos
                {
606 42800be8 Panagiotis Kanavos
                    UserName = accountName,
607 42800be8 Panagiotis Kanavos
                    AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]),
608 42800be8 Panagiotis Kanavos
                    StorageUri = new Uri(root + accountName),
609 42800be8 Panagiotis Kanavos
                    BlockHash=accountInfo.BlockHash,
610 42800be8 Panagiotis Kanavos
                    BlockSize=accountInfo.BlockSize,
611 42800be8 Panagiotis Kanavos
                    Token=accountInfo.Token
612 42800be8 Panagiotis Kanavos
                };
613 42800be8 Panagiotis Kanavos
            }
614 42800be8 Panagiotis Kanavos
            else
615 42800be8 Panagiotis Kanavos
            {
616 42800be8 Panagiotis Kanavos
                accountName = UserName;
617 42800be8 Panagiotis Kanavos
                container = parts[0];                
618 42800be8 Panagiotis Kanavos
            }
619 c92e02f3 Panagiotis Kanavos
620 c92e02f3 Panagiotis Kanavos
            return Task.Factory.StartNew(() =>
621 c92e02f3 Panagiotis Kanavos
            {
622 c92e02f3 Panagiotis Kanavos
                var client = new CloudFilesClient(accountInfo);
623 c92e02f3 Panagiotis Kanavos
                var containerInfo = client.GetContainerInfo(accountName, container);
624 c92e02f3 Panagiotis Kanavos
                return containerInfo;
625 c92e02f3 Panagiotis Kanavos
            });
626 42800be8 Panagiotis Kanavos
        }
627 d78cbf09 Panagiotis Kanavos
    }
628 d78cbf09 Panagiotis Kanavos
}