Revision 283809f3

b/trunk/Pithos.Client.Test/Pithos.Client.Test.csproj
68 68
    <Compile Include="Properties\AssemblyInfo.cs" />
69 69
  </ItemGroup>
70 70
  <ItemGroup>
71
    <ProjectReference Include="..\Pithos.Client\Pithos.Client.csproj">
72
      <Project>{5AC90E5E-60C6-4F53-9444-6088BD7BC929}</Project>
73
      <Name>Pithos.Client</Name>
74
    </ProjectReference>
75 71
    <ProjectReference Include="..\Pithos.Interfaces\Pithos.Interfaces.csproj">
76 72
      <Project>{7EEFF32F-CCF8-436A-9E0B-F40434C09AF4}</Project>
77 73
      <Name>Pithos.Interfaces</Name>
b/trunk/Pithos.Client.WPF/Pithos.Client.WPF.csproj
69 69
  <PropertyGroup>
70 70
    <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
71 71
  </PropertyGroup>
72
  <PropertyGroup>
73
    <ApplicationIcon>Images\Tray.ico</ApplicationIcon>
74
  </PropertyGroup>
72 75
  <ItemGroup>
73 76
    <Reference Include="System" />
74 77
    <Reference Include="System.ComponentModel.Composition" />
b/trunk/Pithos.Core.Test/MockStatusKeeper.cs
62 62
            throw new NotImplementedException();
63 63
        }
64 64

  
65
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus)
66
        {
67
            if (String.IsNullOrWhiteSpace(path))
68
                throw new ArgumentNullException("path", "path can't be empty");
69
            SetFileStatus(path, fileStatus);
70
            SetFileOverlayStatus(path, overlayStatus);
71
        }
72

  
73
        public void StoreInfo(string path, ObjectInfo objectInfo)
74
        {
75
            if (String.IsNullOrWhiteSpace(path))
76
                throw new ArgumentNullException("path", "path can't be empty");
77
            if (objectInfo == null)
78
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
79

  
80
            _statusCache[path] = FileStatus.Unchanged;
81
            _overlayCache[path] = FileOverlayStatus.Normal;
82
            _checksums[path] = objectInfo.Hash;
83

  
84

  
85
        }
86

  
87
        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)
88
        {
89
            throw new NotImplementedException();
90
        }
91

  
92
        public void SetStatus(string path, Action<FileState> setter)
93
        {
94
            throw new NotImplementedException();
95
        }
96

  
97
        ConcurrentDictionary<string, NetworkState> _networkState = new ConcurrentDictionary<string, NetworkState>();
98

  
99

  
100
        public void SetNetworkState(string path, NetworkState state)
101
        {
102
            _networkState[path.ToLower()] = state;
103
            //Removing may fail so we store the "None" value anyway
104
            if (state == NetworkState.None)
105
            {
106
                NetworkState oldState;
107
                _networkState.TryRemove(path, out oldState);
108
            }
109
        }
110

  
111
        public NetworkState GetNetworkState(string path)
112
        {
113
            NetworkState state;
114
            if (_networkState.TryGetValue(path, out state))
115
                return state;
116
            return NetworkState.None;
117
        }
118

  
65 119

  
66 120
        private PithosStatus _pithosStatus = PithosStatus.InSynch;
67 121
        public void SetPithosStatus(PithosStatus status)
b/trunk/Pithos.Core.Test/Pithos.Core.Test.csproj
71 71
    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
72 72
  </PropertyGroup>
73 73
  <ItemGroup>
74
    <Reference Include="Castle.ActiveRecord, Version=3.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL" />
74 75
    <Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
75 76
      <HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
76 77
    </Reference>
b/trunk/Pithos.Core/FileState.cs
38 38

  
39 39
        [Property]
40 40
        public string Checksum { get; set; }
41

  
41 42
    }
43

  
44
  
42 45
}
b/trunk/Pithos.Core/IStatusKeeper.cs
1 1
using System;
2 2
using System.Collections.Generic;
3 3
using System.Diagnostics.Contracts;
4
using System.IO;
4 5
using System.Linq;
5 6
using Pithos.Interfaces;
6 7

  
......
19 20
        FileOverlayStatus GetFileOverlayStatus(string path);
20 21
        IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths);
21 22
        void Stop();
23
        void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus);
24
        void StoreInfo(string path, ObjectInfo objectInfo);
25
        T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue );
26
        void SetStatus(string path, Action<FileState> setter);        
27
        void SetNetworkState(string fileName, NetworkState uploading);
28
        NetworkState GetNetworkState(string fileName);
22 29
    }
23 30

  
24 31
    [ContractClassFor(typeof(IStatusKeeper))]
......
78 85
            
79 86
        }
80 87

  
88
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus)
89
        {
90
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
91
        }
92

  
93
        public void StoreInfo(string path, ObjectInfo objectInfo)
94
        {
95
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
96
            Contract.Requires(objectInfo!=null);            
97
        }
98

  
99
        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)
100
        {
101
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
102
            Contract.Requires(getter!=null);
103

  
104
            return default(T);
105
        }
106

  
107
        public void SetStatus(string path, Action<FileState> setter)
108
        {
109
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
110
            Contract.Requires(setter != null);
111
        }
112

  
113
        public void SetNetworkState(string path, NetworkState uploading)
114
        {
115
            Contract.Requires(!String.IsNullOrWhiteSpace(path));            
116
        }
117

  
118
        public NetworkState GetNetworkState(string path)
119
        {
120
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
121

  
122
            return default(NetworkState);
123
        }
124

  
81 125
        public void ClearFileStatus(string path)
82 126
        {
83 127
            Contract.Requires(!String.IsNullOrWhiteSpace(path));
b/trunk/Pithos.Core/InMemStatusChecker.cs
73 73
            return _pithosStatus;
74 74
        }
75 75

  
76
    public void SetStatus(string path, Action<FileState> setter)
77
        {
78
            throw new NotImplementedException();
79
        }
80

  
81
        ConcurrentDictionary<string, NetworkState> _networkState = new ConcurrentDictionary<string, NetworkState>();
82

  
83
    
84
        public void SetNetworkState(string path, NetworkState state)
85
        {
86
            _networkState[path.ToLower()] = state;
87
            //Removing may fail so we store the "None" value anyway
88
            if (state == NetworkState.None)
89
            {
90
                NetworkState oldState;
91
                _networkState.TryRemove(path, out oldState);
92
            }
93
        }
94

  
95
        public NetworkState GetNetworkState(string path)
96
        {
97
            NetworkState state;
98
            if (_networkState.TryGetValue(path, out state))
99
                return state;
100
            return NetworkState.None;
101
        }
102

  
76 103
        public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
77 104
        {
78 105
            _overlayCache[path] = overlayStatus;
......
97 124
            _statusCache[path] = status;
98 125
        }
99 126

  
127
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus)
128
        {
129
            if (String.IsNullOrWhiteSpace(path))
130
                throw new ArgumentNullException("path","path can't be empty");
131
            _statusCache[path] = fileStatus;
132
            _overlayCache[path] = overlayStatus;
133
        }
134

  
135
        public void StoreInfo(string path, ObjectInfo objectInfo)
136
        {
137
            if (String.IsNullOrWhiteSpace(path))
138
                throw new ArgumentNullException("path", "path can't be empty");
139
            if (objectInfo == null)
140
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
141

  
142
            _statusCache[path] = FileStatus.Unchanged;
143
            _overlayCache[path] = FileOverlayStatus.Normal;
144
            _checksums[path] = objectInfo.Hash;
145

  
146

  
147
        }
148

  
149
        public T GetStatus<T>(string path, Func<FileState, T> getter, T defaultValue)
150
        {
151
            throw new NotImplementedException();
152
        }
153

  
100 154
        public FileStatus GetFileStatus(string path)
101 155
        {
102 156
            if (!_statusCache.ContainsKey(path))
b/trunk/Pithos.Core/PithosMonitor.cs
272 272
            }
273 273
        }
274 274

  
275
        private BlockingCollection<ListenerAction> _listenerActions=new BlockingCollection<ListenerAction>();
275
        private BlockingCollection<ListenerAction> _networkActions=new BlockingCollection<ListenerAction>();
276 276

  
277 277
        private Timer timer;
278 278

  
......
303 303
                                      var pithosDir = new DirectoryInfo(accountPath);
304 304
                                      
305 305
                                      var remoteFiles = from info in remoteObjects
306
                                                    select info.Name;
306
                                                    select info.Name.ToLower();
307 307
                                      
308 308
                                      var onlyLocal = from localFile in pithosDir.EnumerateFiles()
309
                                                      where !remoteFiles.Contains(localFile.Name) 
309
                                                      where !remoteFiles.Contains(localFile.Name.ToLower()) 
310 310
                                                      select new ListenerAction(CloudActionType.UploadUnconditional, localFile,null);
311
                                      
312
                                      
313
                                    
314 311

  
315
                                      var localNames =pithosDir.EnumerateFiles().Select(info => info.Name);
312

  
313

  
314
                                      var localNames = from info in pithosDir.EnumerateFiles()
315
                                                           select info.Name.ToLower();
316

  
316 317
                                      var onlyRemote = from upFile in remoteObjects
317
                                                       where !localNames.Contains(upFile.Name)
318
                                                       where !localNames.Contains(upFile.Name.ToLower())
318 319
                                                       select new ListenerAction(CloudActionType.DownloadUnconditional,null,upFile);
319 320

  
320 321

  
321 322
                                      var commonObjects = from  upFile in remoteObjects
322 323
                                                            join  localFile in pithosDir.EnumerateFiles()
323
                                                                on upFile.Name equals localFile.Name 
324
                                                                on upFile.Name.ToLower() equals localFile.Name.ToLower() 
324 325
                                                            select new ListenerAction(CloudActionType.Download, localFile, upFile);
325 326

  
326 327
                                      var uniques =
327 328
                                          onlyLocal.Union(onlyRemote).Union(commonObjects)
328
                                              .Except(_listenerActions,new LocalFileComparer());
329
                                              .Except(_networkActions,new LocalFileComparer());
329 330
                                      
330
                                      _listenerActions.AddFromEnumerable(uniques, false);
331
                                      _networkActions.AddFromEnumerable(uniques, false);
331 332

  
332 333
                                      Trace.TraceInformation("[LISTENER] End Processing");
333 334
                                      
......
348 349

  
349 350
        private void ProcessListenerActions()
350 351
        {
351
            foreach(var action in _listenerActions.GetConsumingEnumerable())
352
            foreach(var action in _networkActions.GetConsumingEnumerable())
352 353
            {
353 354
                Trace.TraceInformation("[ACTION] Start Processing {0}:{1}->{2}",action.Action,action.LocalFile,action.CloudFile);
354 355
                var localFile = action.LocalFile;
......
393 394
                    Trace.TraceError("[REQUEUE] {0} : {1} -> {2} due to exception\r\n{3}",
394 395
                                    action.Action, action.LocalFile,action.CloudFile,exc);                    
395 396

  
396
                    _listenerActions.Add(action);
397
                    _networkActions.Add(action);
397 398
                }
398 399
            }
399 400
        }
400 401

  
401
        private void DownloadCloudFile(string container, string fileName, string localPath)
402
        {
403
            using (var upstream = CloudClient.GetObject(container, fileName))
404
            using (var fileStream = File.OpenWrite(localPath))
405
            {
406
                upstream.CopyTo(fileStream);
407
            }
408
        }
402
      
409 403

  
410 404
        private void StartMonitoringFiles(string path)
411 405
        {
......
416 410
            _watcher.Renamed += OnRenameEvent;
417 411
            _watcher.EnableRaisingEvents = true;
418 412

  
419
            Task.Factory.StartNew(() =>
420
                                      {
421
                                          foreach (var state in _fileEvents.GetConsumingEnumerable())
422
                                          {
423
                                              try
424
                                              {
425
                                                  UpdateFileStatus(state);
426
                                                  UpdateOverlayStatus(state);
427
                                                  UpdateFileChecksum(state);
428
                                                  _uploadEvents.Add(state);                                                  
429
                                              }
430
                                              catch (OperationCanceledException)
431
                                              {
432
                                                  throw;
433
                                              }
434
                                              catch(Exception ex)
435
                                              {}
436
                                          }
437
                                          
438
                                      },_cancellationSource.Token);
413
            Task.Factory.StartNew(ProcesFileEvents,_cancellationSource.Token);
414
        }
415

  
416
        private void ProcesFileEvents()
417
        {
418
            foreach (var state in _fileEvents.GetConsumingEnumerable())
419
            {
420
                try
421
                {
422
                    var networkState=StatusKeeper.GetNetworkState(state.Path);
423
                    //Skip if the file is already being downloaded or uploaded and 
424
                    //the change is create or modify
425
                    if (networkState != NetworkState.None && 
426
                        (
427
                            state.TriggeringChange==WatcherChangeTypes.Created ||
428
                            state.TriggeringChange==WatcherChangeTypes.Changed
429
                        ))
430
                        continue;
431
                    UpdateFileStatus(state);
432
                    UpdateOverlayStatus(state);
433
                    UpdateFileChecksum(state);
434
                    _uploadEvents.Add(state);
435
                }
436
                catch (OperationCanceledException exc)
437
                {
438
                    Trace.TraceError("[ERROR] File Event Processing:\r{0}", exc);
439
                    throw;
440
                }
441
                catch (Exception exc)
442
                {
443
                    Trace.TraceError("[ERROR] File Event Processing:\r{0}",exc);
444
                }
445
            }
439 446
        }
440 447

  
441 448
        private void StartSending()
......
510 517
            this.StatusKeeper.RemoveFileOverlayStatus(fileName);            
511 518
        }
512 519

  
520
        private void DownloadCloudFile(string container, string fileName, string localPath)
521
        {
522
            StatusKeeper.SetNetworkState(localPath,NetworkState.Downloading);
523
            CloudClient.GetObject(container, fileName, localPath)
524
            .ContinueWith(t=>
525
                CloudClient.GetObjectInfo(container,fileName))
526
            .ContinueWith(t=>
527
                StatusKeeper.StoreInfo(fileName,t.Result))
528
            .ContinueWith(t=>
529
                StatusKeeper.SetNetworkState(localPath,NetworkState.None))
530
            .Wait();
531
        }
532

  
513 533
        private void UploadCloudFile(string fileName, long fileSize, string path,string hash)
514 534
        {
515 535
            Contract.Requires(!Path.IsPathRooted(fileName));
516
            //Even if GetObjectInfo times out, we can proceed with the upload
536

  
537
            StatusKeeper.SetNetworkState(fileName,NetworkState.Uploading);
538
            
539
            //Even if GetObjectInfo times out, we can proceed with the upload            
517 540
            var info = CloudClient.GetObjectInfo("PITHOS", fileName);
518 541
            Task.Factory.StartNew(() =>
519 542
            {
......
524 547
                    .ContinueWith(t => 
525 548
                        CloudClient.PutObject("PITHOS", fileName, path, hash));
526 549
                }
550
                else
551
                {
552
                    this.StatusKeeper.StoreInfo(path,info);
553
                }
527 554
            }
528 555
            )
529
            .ContinueWith(t =>{
530
                        this.StatusKeeper.SetFileStatus(path, FileStatus.Unchanged);
531
                        this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Normal);
532
            })
556
            .ContinueWith(t => 
557
                this.StatusKeeper.SetFileState(path, FileStatus.Unchanged, FileOverlayStatus.Normal))
558
                .ContinueWith(t=>
559
                    this.StatusKeeper.SetNetworkState(path,NetworkState.None))
533 560
            .Wait();
534 561
            Workflow.RaiseChangeNotification(path);
535 562
        }
b/trunk/Pithos.Core/StatusKeeper.cs
6 6
using System.Diagnostics.Contracts;
7 7
using System.IO;
8 8
using System.Linq;
9
using System.Linq.Expressions;
9 10
using System.Security.Cryptography;
10 11
using System.Text;
11 12
using System.Threading;
......
49 50
        {
50 51
            _statusUpdateQueue.CompleteAdding();
51 52
        }
52

  
53
        public FileOverlayStatus GetFileOverlayStatus(string path)
54
        {
55
            try
56
            {
57
                var state = FileState.TryFind(path.ToLower());
58
                return state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
59
            }
60
            catch (Exception exc)
61
            {
62
                Trace.TraceError(exc.ToString());
63
                return FileOverlayStatus.Unversioned;
64
            }
65
        }
53
       
66 54

  
67 55
        public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths)
68 56
        {            
......
132 120
            return _pithosStatus;
133 121
        }
134 122

  
123

  
124
        ConcurrentDictionary<string,NetworkState> _networkState=new ConcurrentDictionary<string, NetworkState>();
125

  
126
        public void SetNetworkState(string path,NetworkState state)
127
        {
128
            _networkState[path.ToLower()] = state;
129
            //Removing may fail so we store the "None" value anyway
130
            if (state == NetworkState.None)
131
            {
132
                NetworkState oldState;
133
                _networkState.TryRemove(path, out oldState);
134
            }
135
        }
136

  
137
        public NetworkState GetNetworkState(string path)
138
        {
139
            NetworkState state ;
140
            if (_networkState.TryGetValue(path, out state))
141
                return state;
142
            return NetworkState.None;
143
        }
144

  
145

  
146
        public T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue )
147
        {
148

  
149

  
150
            try
151
            {
152
                var state = FileState.TryFind(path.ToLower());
153
                return state == null ? defaultValue : getter(state);
154
            }
155
            catch (Exception exc)
156
            {
157
                Trace.TraceError(exc.ToString());
158
                return defaultValue;
159
            }
160
        }
161

  
162
        /// <summary>
163
        /// Sets the status of a file, creating a new FileState entry if one doesn't already exist.
164
        /// </summary>
165
        /// <param name="path"></param>
166
        /// <param name="setter"></param>
167
        public void SetStatus(string path,Action<FileState> setter)
168
        {
169
            if (String.IsNullOrWhiteSpace(path))
170
                throw new ArgumentNullException("path", "path can't be empty");
171

  
172
            if (setter==null)
173
                throw new ArgumentNullException("setter", "setter can't be empty");
174

  
175
            _statusUpdateQueue.Add(() =>
176
            {
177
                var filePath = path.ToLower();
178
                var state = FileState.TryFind(filePath);
179
                if (state != null)
180
                {
181
                    setter(state);
182
                    state.Update();
183
                }
184
                else
185
                {
186
                    state = new FileState {FilePath = filePath};
187
                    setter(state);
188
                    state.Save();
189
                }
190
            });
191
        }
192

  
193
        /// <summary>
194
        /// Sets the status of a file only if the file already exists
195
        /// </summary>
196
        /// <param name="path"></param>
197
        /// <param name="setter"></param>
198
        private void UpdateStatus(string path, Action<FileState> setter)
199
        {
200
            if (String.IsNullOrWhiteSpace(path))
201
                throw new ArgumentNullException("path", "path can't be empty");
202

  
203
            if (setter == null)
204
                throw new ArgumentNullException("setter", "setter can't be empty");
205

  
206
            _statusUpdateQueue.Add(() =>
207
            {
208
                var filePath = path.ToLower();
209
                var state = FileState.TryFind(filePath);
210
                if (state == null)
211
                {
212
                    Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", filePath);
213
                    return;
214
                }
215
                setter(state);
216
                state.Save();
217
            });
218
        }
219

  
220
        public FileOverlayStatus GetFileOverlayStatus(string path)
221
        {
222
            try
223
            {
224
                var state = FileState.TryFind(path.ToLower());
225
                return state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
226
            }
227
            catch (Exception exc)
228
            {
229
                Trace.TraceError(exc.ToString());
230
                return FileOverlayStatus.Unversioned;
231
            }
232
        }
233

  
135 234
        public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
136 235
        {
137
            _statusUpdateQueue.Add(() => 
138
                InnerSetOverlayStatus(path, overlayStatus));
236
            SetStatus(path,s=>s.OverlayStatus=overlayStatus);
139 237
        }
140 238

  
141
        private static void InnerSetOverlayStatus(string path, FileOverlayStatus overlayStatus)
239
       /* private static void InnerSetOverlayStatus(string path, FileOverlayStatus overlayStatus)
142 240
        {
143
            var state = FileState.TryFind(path.ToLower());
241
            var filePath = path.ToLower();
242
            var state = FileState.TryFind(filePath);
144 243
            if (state != null)
145 244
            {
146 245
                state.OverlayStatus = overlayStatus;
......
149 248
            else
150 249
            {
151 250
                state = new FileState
152
                            {FilePath = path, OverlayStatus = overlayStatus};
251
                            {FilePath = filePath, OverlayStatus = overlayStatus};
153 252
                state.Save();
154 253
            }
155
        }
254
        }*/
156 255

  
157 256
        public void RemoveFileOverlayStatus(string path)
158 257
        {
......
184 283
            state.Update();
185 284
        }
186 285

  
187
        public void SetFileStatus(string path, FileStatus status)
286
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus)
188 287
        {
189
            _statusUpdateQueue.Add(() =>
190
                InnerSetFileStatus(path, status));
288
            if (String.IsNullOrWhiteSpace(path))
289
                throw new ArgumentNullException("path", "path can't be empty");
290
            
291
            UpdateStatus(path,state=>
292
                                  {
293
                                      state.FileStatus = fileStatus;
294
                                      state.OverlayStatus = overlayStatus;
295
                                  });            
191 296
        }
192 297

  
193
        private static void InnerSetFileStatus(string path, FileStatus status)
298
        public void StoreInfo(string path,ObjectInfo objectInfo)
194 299
        {
195
            var state = FileState.TryFind(path.ToLower());
300
            if (String.IsNullOrWhiteSpace(path))
301
                throw new ArgumentNullException("path", "path can't be empty");
302
            if (objectInfo==null)
303
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
304

  
305
            var state = FileState.TryFind(path)??new FileState();
306
            state.FilePath = path.ToLower();
307
            state.Checksum = objectInfo.Hash;
308
            state.FileStatus = FileStatus.Unchanged;
309
            state.OverlayStatus = FileOverlayStatus.Normal;            
310
            
311
            state.Save();
312
            
313
        }
314

  
315
        
316
        public void SetFileStatus(string path, FileStatus status)
317
        {            
318
            UpdateStatus(path, state=>state.FileStatus = status);
319
        }
320

  
321

  
322
       /* private static void InnerSetFileStatus(string path, FileStatus status)
323
        {
324
            var filePath = path.ToLower();
325
            var state = FileState.TryFind(filePath);
196 326
            if (state == null)
197 327
            {
198
                Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", path);
328
                Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", filePath);
199 329
                return;
200 330
            }
201 331
            state.FileStatus = status;
202
        }
332
            state.Update();
333
        }*/
203 334

  
204 335
        public FileStatus GetFileStatus(string path)
205 336
        {
......
226 357
            state.Update();
227 358
        }
228 359
    }
360

  
361
    public enum NetworkState
362
    {
363
        None,
364
        Uploading,
365
        Downloading
366
    }
229 367
}
b/trunk/Pithos.Interfaces/ICloudClient.cs
30 30
        void CreateContainer(string container);
31 31
        void DeleteContainer(string container);
32 32
        
33
        Stream GetObject(string container, string objectName);
33
        Task GetObject(string container, string objectName, string fileName);
34 34
        Task PutObject(string container, string objectName, string fileName, string hash = null);
35 35
        void DeleteObject(string container, string objectName);
36 36
        void MoveObject(string container, string oldObjectName, string newObjectName);
......
127 127
            Contract.Requires(!String.IsNullOrWhiteSpace(container));
128 128
        }
129 129

  
130
        public Stream GetObject(string container, string objectName)
130
        public Task GetObject(string container, string objectName, string fileName)
131 131
        {
132 132
            Contract.Requires(!String.IsNullOrWhiteSpace(Token));
133 133
            Contract.Requires(StorageUrl!=null);
134 134
            Contract.Requires(!String.IsNullOrWhiteSpace(container));
135 135
            Contract.Requires(!String.IsNullOrWhiteSpace(objectName));
136 136

  
137
            return default(Stream);
137
            return default(Task);
138 138
        }
139 139

  
140 140
        public Task PutObject(string container, string objectName, string fileName, string hash = null)
......
218 218
            set { _tags = value; }
219 219
        }
220 220

  
221
        public Stream Stream { get; set; }
222

  
221 223
        public static ObjectInfo Empty=new ObjectInfo {Name=String.Empty,Hash=String.Empty,Bytes=0,Content_Type=String.Empty,Last_Modified=DateTime.MinValue};
222 224
    }
223 225
}
b/trunk/Pithos.Network.Test/NetworkOpsTest.cs
120 120
                
121 121

  
122 122
                string downloadFile = "test2.txt";
123
                using (var stream = client.GetObject("Shares", testFileName))
124
                using (var file = File.Create(downloadFile, 4096, FileOptions.DeleteOnClose))
125
                {
126
                    stream.CopyTo(file);
127
                    Assert.IsTrue(File.Exists(downloadFile));
128
                }
123
                client.GetObject("Shares", testFileName, downloadFile)
124
                    .Wait();
125

  
126
                Assert.IsTrue(File.Exists(downloadFile));
129 127
                
130 128
            });
131 129
            
b/trunk/Pithos.Network/CloudFilesClient.cs
372 372
        /// </summary>
373 373
        /// <param name="container"></param>
374 374
        /// <param name="objectName"></param>
375
        /// <param name="fileName"></param>
375 376
        /// <returns></returns>
376 377
        /// <remarks>>This method should have no timeout or a very long one</remarks>
377
        public Stream GetObject(string container, string objectName)
378
        public Task GetObject(string container, string objectName, string fileName)
378 379
        {
379 380
            if (String.IsNullOrWhiteSpace(container))
380 381
                throw new ArgumentNullException("container", "The container property can't be empty");
381 382
            if (String.IsNullOrWhiteSpace(objectName))
382 383
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
383 384

  
384
            var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Get };
385
/*
386
            if (DownloadPercentLimit > 0)
387
                request.TaskOptions = new TaskOptions<int> { RateLimitPercent = DownloadPercentLimit };
388
*/
389
            
390
            var response = _client.Request(request);
391
            
392
            if (response.StatusCode == HttpStatusCode.NotFound)
393
                throw new FileNotFoundException();
394
            if (response.StatusCode == HttpStatusCode.OK)
385
            var request = new RestRequest {Path = container + "/" + objectName, Method = WebMethod.Get};
386
            /*
387
                        if (DownloadPercentLimit > 0)
388
                            request.TaskOptions = new TaskOptions<int> { RateLimitPercent = DownloadPercentLimit };
389
            */
390
            try
391
            {
392
                var url = String.Join("/", new[] {_client.Authority, container, objectName});
393
                var uri = new Uri(url);
394

  
395
                var client = new WebClient();
396
                if (!String.IsNullOrWhiteSpace(_client.Proxy))
397
                    client.Proxy = new WebProxy(_client.Proxy);
398

  
399
                CopyHeaders(_client, client);
400

  
401
                Trace.TraceInformation("[GET] START {0}", objectName);
402
                client.DownloadProgressChanged += (sender, args) => 
403
                    Trace.TraceInformation("[GET PROGRESS] {0} {1}% {2} of {3}",
404
                                    fileName, args.ProgressPercentage,
405
                                    args.BytesReceived,
406
                                    args.TotalBytesToReceive);
407
                
408
                return client.DownloadFileTask(uri, fileName)
409
                    .ContinueWith(download =>
410
                                      {
411
                                          client.Dispose();
412

  
413
                                          if (download.IsFaulted)
414
                                          {
415
                                              Trace.TraceError("[GET] FAIL for {0} with \r{1}", objectName,
416
                                                               download.Exception);
417
                                          }
418
                                          else
419
                                          {
420
                                              Trace.TraceInformation("[GET] END {0}", objectName);                                             
421
                                          }
422
                                      });
423
            }
424
            catch (Exception exc)
395 425
            {
396
                return response.ContentStream;
426
                Trace.TraceError("[GET] END {0} with {1}", objectName, exc);
427
                throw;
397 428
            }
398
            else
399
                throw new WebException(String.Format("GetObject failed with unexpected status code {0}", response.StatusCode));
429

  
430

  
431

  
400 432
        }
401 433

  
402 434
        /// <summary>
......
438 470
                Trace.TraceInformation("[PUT] START {0}", objectName);
439 471
                client.UploadProgressChanged += (sender, args) =>
440 472
                {
441
                    Trace.TraceInformation("[PROGRESS] {0} {1}% {2} of {3}", fileName, args.ProgressPercentage, args.BytesSent, args.TotalBytesToSend);
473
                    Trace.TraceInformation("[PUT PROGRESS] {0} {1}% {2} of {3}", fileName, args.ProgressPercentage, args.BytesSent, args.TotalBytesToSend);
442 474
                };
443 475
               
444 476
                return client.UploadFileTask(uri, "PUT", fileName)
b/trunk/Pithos.Setup.x64/Pithos.Setup.x64.vdproj
1
๏ปฟ"DeployProject"
2
{
3
"VSVersion" = "3:800"
4
"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}"
5
"IsWebType" = "8:FALSE"
6
"ProjectName" = "8:Pithos.Setup.x64"
7
"LanguageId" = "3:1033"
8
"CodePage" = "3:1252"
9
"UILanguageId" = "3:1033"
10
"SccProjectName" = "8:"
11
"SccLocalPath" = "8:"
12
"SccAuxPath" = "8:"
13
"SccProvider" = "8:"
14
    "Hierarchy"
15
    {
16
        "Entry"
17
        {
18
        "MsmKey" = "8:_0E4F95BDB07F23F411C53FB6C2E602F7"
19
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
20
        "MsmSig" = "8:_UNDEFINED"
21
        }
22
        "Entry"
23
        {
24
        "MsmKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE"
25
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
26
        "MsmSig" = "8:_UNDEFINED"
27
        }
28
        "Entry"
29
        {
30
        "MsmKey" = "8:_19A1385E2CA0B02EAB082C45FB563106"
31
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
32
        "MsmSig" = "8:_UNDEFINED"
33
        }
34
        "Entry"
35
        {
36
        "MsmKey" = "8:_19A1385E2CA0B02EAB082C45FB563106"
37
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
38
        "MsmSig" = "8:_UNDEFINED"
39
        }
40
        "Entry"
41
        {
42
        "MsmKey" = "8:_19A1385E2CA0B02EAB082C45FB563106"
43
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
44
        "MsmSig" = "8:_UNDEFINED"
45
        }
46
        "Entry"
47
        {
48
        "MsmKey" = "8:_1C947FDDE7225C5E2E28957C22AEBD69"
49
        "OwnerKey" = "8:_CF5ACB8C98D779B9A84FD89746C3A547"
50
        "MsmSig" = "8:_UNDEFINED"
51
        }
52
        "Entry"
53
        {
54
        "MsmKey" = "8:_1C947FDDE7225C5E2E28957C22AEBD69"
55
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
56
        "MsmSig" = "8:_UNDEFINED"
57
        }
58
        "Entry"
59
        {
60
        "MsmKey" = "8:_1C947FDDE7225C5E2E28957C22AEBD69"
61
        "OwnerKey" = "8:_A2F4B8CF23FA43E69AF60DA69D47AA18"
62
        "MsmSig" = "8:_UNDEFINED"
63
        }
64
        "Entry"
65
        {
66
        "MsmKey" = "8:_1C947FDDE7225C5E2E28957C22AEBD69"
67
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
68
        "MsmSig" = "8:_UNDEFINED"
69
        }
70
        "Entry"
71
        {
72
        "MsmKey" = "8:_2837CB1EABE794B2B8C0028FDCFEA1C0"
73
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
74
        "MsmSig" = "8:_UNDEFINED"
75
        }
76
        "Entry"
77
        {
78
        "MsmKey" = "8:_311197E10704448D93A69A8EC39C3C80"
79
        "OwnerKey" = "8:_UNDEFINED"
80
        "MsmSig" = "8:_UNDEFINED"
81
        }
82
        "Entry"
83
        {
84
        "MsmKey" = "8:_379682952A41C4DD701D113A41CD0ACC"
85
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
86
        "MsmSig" = "8:_UNDEFINED"
87
        }
88
        "Entry"
89
        {
90
        "MsmKey" = "8:_379682952A41C4DD701D113A41CD0ACC"
91
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
92
        "MsmSig" = "8:_UNDEFINED"
93
        }
94
        "Entry"
95
        {
96
        "MsmKey" = "8:_379682952A41C4DD701D113A41CD0ACC"
97
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
98
        "MsmSig" = "8:_UNDEFINED"
99
        }
100
        "Entry"
101
        {
102
        "MsmKey" = "8:_412610FA5B854CE1B90857177A4DF634"
103
        "OwnerKey" = "8:_UNDEFINED"
104
        "MsmSig" = "8:_UNDEFINED"
105
        }
106
        "Entry"
107
        {
108
        "MsmKey" = "8:_413A3C9A9C848F0F0E34C29B1C919557"
109
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
110
        "MsmSig" = "8:_UNDEFINED"
111
        }
112
        "Entry"
113
        {
114
        "MsmKey" = "8:_413A3C9A9C848F0F0E34C29B1C919557"
115
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
116
        "MsmSig" = "8:_UNDEFINED"
117
        }
118
        "Entry"
119
        {
120
        "MsmKey" = "8:_413A3C9A9C848F0F0E34C29B1C919557"
121
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
122
        "MsmSig" = "8:_UNDEFINED"
123
        }
124
        "Entry"
125
        {
126
        "MsmKey" = "8:_413A3C9A9C848F0F0E34C29B1C919557"
127
        "OwnerKey" = "8:_476D990A74530772679162FBBFE0FCF4"
128
        "MsmSig" = "8:_UNDEFINED"
129
        }
130
        "Entry"
131
        {
132
        "MsmKey" = "8:_413A3C9A9C848F0F0E34C29B1C919557"
133
        "OwnerKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
134
        "MsmSig" = "8:_UNDEFINED"
135
        }
136
        "Entry"
137
        {
138
        "MsmKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
139
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
140
        "MsmSig" = "8:_UNDEFINED"
141
        }
142
        "Entry"
143
        {
144
        "MsmKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
145
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
146
        "MsmSig" = "8:_UNDEFINED"
147
        }
148
        "Entry"
149
        {
150
        "MsmKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
151
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
152
        "MsmSig" = "8:_UNDEFINED"
153
        }
154
        "Entry"
155
        {
156
        "MsmKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
157
        "OwnerKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
158
        "MsmSig" = "8:_UNDEFINED"
159
        }
160
        "Entry"
161
        {
162
        "MsmKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
163
        "OwnerKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
164
        "MsmSig" = "8:_UNDEFINED"
165
        }
166
        "Entry"
167
        {
168
        "MsmKey" = "8:_46914103D6A9E95AD780FA7F8D2149CA"
169
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
170
        "MsmSig" = "8:_UNDEFINED"
171
        }
172
        "Entry"
173
        {
174
        "MsmKey" = "8:_46914103D6A9E95AD780FA7F8D2149CA"
175
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
176
        "MsmSig" = "8:_UNDEFINED"
177
        }
178
        "Entry"
179
        {
180
        "MsmKey" = "8:_46914103D6A9E95AD780FA7F8D2149CA"
181
        "OwnerKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
182
        "MsmSig" = "8:_UNDEFINED"
183
        }
184
        "Entry"
185
        {
186
        "MsmKey" = "8:_46914103D6A9E95AD780FA7F8D2149CA"
187
        "OwnerKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
188
        "MsmSig" = "8:_UNDEFINED"
189
        }
190
        "Entry"
191
        {
192
        "MsmKey" = "8:_476D990A74530772679162FBBFE0FCF4"
193
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
194
        "MsmSig" = "8:_UNDEFINED"
195
        }
196
        "Entry"
197
        {
198
        "MsmKey" = "8:_476D990A74530772679162FBBFE0FCF4"
199
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
200
        "MsmSig" = "8:_UNDEFINED"
201
        }
202
        "Entry"
203
        {
204
        "MsmKey" = "8:_476D990A74530772679162FBBFE0FCF4"
205
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
206
        "MsmSig" = "8:_UNDEFINED"
207
        }
208
        "Entry"
209
        {
210
        "MsmKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
211
        "OwnerKey" = "8:_379682952A41C4DD701D113A41CD0ACC"
212
        "MsmSig" = "8:_UNDEFINED"
213
        }
214
        "Entry"
215
        {
216
        "MsmKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
217
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
218
        "MsmSig" = "8:_UNDEFINED"
219
        }
220
        "Entry"
221
        {
222
        "MsmKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
223
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
224
        "MsmSig" = "8:_UNDEFINED"
225
        }
226
        "Entry"
227
        {
228
        "MsmKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
229
        "OwnerKey" = "8:_476D990A74530772679162FBBFE0FCF4"
230
        "MsmSig" = "8:_UNDEFINED"
231
        }
232
        "Entry"
233
        {
234
        "MsmKey" = "8:_4CFFEFA8D3F3865F15FEA354C6BF4ECC"
235
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
236
        "MsmSig" = "8:_UNDEFINED"
237
        }
238
        "Entry"
239
        {
240
        "MsmKey" = "8:_71AB7BB89699C43F04EFBBD41DFF976E"
241
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
242
        "MsmSig" = "8:_UNDEFINED"
243
        }
244
        "Entry"
245
        {
246
        "MsmKey" = "8:_71AB7BB89699C43F04EFBBD41DFF976E"
247
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
248
        "MsmSig" = "8:_UNDEFINED"
249
        }
250
        "Entry"
251
        {
252
        "MsmKey" = "8:_71AB7BB89699C43F04EFBBD41DFF976E"
253
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
254
        "MsmSig" = "8:_UNDEFINED"
255
        }
256
        "Entry"
257
        {
258
        "MsmKey" = "8:_71AB7BB89699C43F04EFBBD41DFF976E"
259
        "OwnerKey" = "8:_2837CB1EABE794B2B8C0028FDCFEA1C0"
260
        "MsmSig" = "8:_UNDEFINED"
261
        }
262
        "Entry"
263
        {
264
        "MsmKey" = "8:_74535AE0FDD2421E81F24E0DB0554D26"
265
        "OwnerKey" = "8:_UNDEFINED"
266
        "MsmSig" = "8:_UNDEFINED"
267
        }
268
        "Entry"
269
        {
270
        "MsmKey" = "8:_75D885F375DFDB481975C88F857E2ACF"
271
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
272
        "MsmSig" = "8:_UNDEFINED"
273
        }
274
        "Entry"
275
        {
276
        "MsmKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
277
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
278
        "MsmSig" = "8:_UNDEFINED"
279
        }
280
        "Entry"
281
        {
282
        "MsmKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
283
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
284
        "MsmSig" = "8:_UNDEFINED"
285
        }
286
        "Entry"
287
        {
288
        "MsmKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
289
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
290
        "MsmSig" = "8:_UNDEFINED"
291
        }
292
        "Entry"
293
        {
294
        "MsmKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
295
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
296
        "MsmSig" = "8:_UNDEFINED"
297
        }
298
        "Entry"
299
        {
300
        "MsmKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
301
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
302
        "MsmSig" = "8:_UNDEFINED"
303
        }
304
        "Entry"
305
        {
306
        "MsmKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
307
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
308
        "MsmSig" = "8:_UNDEFINED"
309
        }
310
        "Entry"
311
        {
312
        "MsmKey" = "8:_9419C61DF5F3441099A56E07565699F0"
313
        "OwnerKey" = "8:_UNDEFINED"
314
        "MsmSig" = "8:_UNDEFINED"
315
        }
316
        "Entry"
317
        {
318
        "MsmKey" = "8:_9F55CE39394926A083741C3E2824DE59"
319
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
320
        "MsmSig" = "8:_UNDEFINED"
321
        }
322
        "Entry"
323
        {
324
        "MsmKey" = "8:_A2F4B8CF23FA43E69AF60DA69D47AA18"
325
        "OwnerKey" = "8:_UNDEFINED"
326
        "MsmSig" = "8:_UNDEFINED"
327
        }
328
        "Entry"
329
        {
330
        "MsmKey" = "8:_ACC23150A2A1275D34D53AA04F5D868E"
331
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
332
        "MsmSig" = "8:_UNDEFINED"
333
        }
334
        "Entry"
335
        {
336
        "MsmKey" = "8:_ACC23150A2A1275D34D53AA04F5D868E"
337
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
338
        "MsmSig" = "8:_UNDEFINED"
339
        }
340
        "Entry"
341
        {
342
        "MsmKey" = "8:_ACC23150A2A1275D34D53AA04F5D868E"
343
        "OwnerKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
344
        "MsmSig" = "8:_UNDEFINED"
345
        }
346
        "Entry"
347
        {
348
        "MsmKey" = "8:_ACC23150A2A1275D34D53AA04F5D868E"
349
        "OwnerKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
350
        "MsmSig" = "8:_UNDEFINED"
351
        }
352
        "Entry"
353
        {
354
        "MsmKey" = "8:_BAA515E0FCDE402CBF2A6FF3D94A0B83"
355
        "OwnerKey" = "8:_UNDEFINED"
356
        "MsmSig" = "8:_UNDEFINED"
357
        }
358
        "Entry"
359
        {
360
        "MsmKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
361
        "OwnerKey" = "8:_UNDEFINED"
362
        "MsmSig" = "8:_UNDEFINED"
363
        }
364
        "Entry"
365
        {
366
        "MsmKey" = "8:_C4EB6477683944848E47C160C41EA94A"
367
        "OwnerKey" = "8:_UNDEFINED"
368
        "MsmSig" = "8:_UNDEFINED"
369
        }
370
        "Entry"
371
        {
372
        "MsmKey" = "8:_C7FAC6DF0866992BDABC6B70456C92F1"
373
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
374
        "MsmSig" = "8:_UNDEFINED"
375
        }
376
        "Entry"
377
        {
378
        "MsmKey" = "8:_C7FAC6DF0866992BDABC6B70456C92F1"
379
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
380
        "MsmSig" = "8:_UNDEFINED"
381
        }
382
        "Entry"
383
        {
384
        "MsmKey" = "8:_CE1C7673CEC14F70AFCF2B48FF8B3D37"
385
        "OwnerKey" = "8:_UNDEFINED"
386
        "MsmSig" = "8:_UNDEFINED"
387
        }
388
        "Entry"
389
        {
390
        "MsmKey" = "8:_CF5ACB8C98D779B9A84FD89746C3A547"
391
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
392
        "MsmSig" = "8:_UNDEFINED"
393
        }
394
        "Entry"
395
        {
396
        "MsmKey" = "8:_CF5ACB8C98D779B9A84FD89746C3A547"
397
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
398
        "MsmSig" = "8:_UNDEFINED"
399
        }
400
        "Entry"
401
        {
402
        "MsmKey" = "8:_CF5ACB8C98D779B9A84FD89746C3A547"
403
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
404
        "MsmSig" = "8:_UNDEFINED"
405
        }
406
        "Entry"
407
        {
408
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
409
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
410
        "MsmSig" = "8:_UNDEFINED"
411
        }
412
        "Entry"
413
        {
414
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
415
        "OwnerKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE"
416
        "MsmSig" = "8:_UNDEFINED"
417
        }
418
        "Entry"
419
        {
420
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
421
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
422
        "MsmSig" = "8:_UNDEFINED"
423
        }
424
        "Entry"
425
        {
426
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
427
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
428
        "MsmSig" = "8:_UNDEFINED"
429
        }
430
        "Entry"
431
        {
432
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
433
        "OwnerKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
434
        "MsmSig" = "8:_UNDEFINED"
435
        }
436
        "Entry"
437
        {
438
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
439
        "OwnerKey" = "8:_BAA515E0FCDE402CBF2A6FF3D94A0B83"
440
        "MsmSig" = "8:_UNDEFINED"
441
        }
442
        "Entry"
443
        {
444
        "MsmKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
445
        "OwnerKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
446
        "MsmSig" = "8:_UNDEFINED"
447
        }
448
        "Entry"
449
        {
450
        "MsmKey" = "8:_E5247C57FCF8FDC4526119494C9CA91D"
451
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
452
        "MsmSig" = "8:_UNDEFINED"
453
        }
454
        "Entry"
455
        {
456
        "MsmKey" = "8:_E5247C57FCF8FDC4526119494C9CA91D"
457
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
458
        "MsmSig" = "8:_UNDEFINED"
459
        }
460
        "Entry"
461
        {
462
        "MsmKey" = "8:_E5247C57FCF8FDC4526119494C9CA91D"
463
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
464
        "MsmSig" = "8:_UNDEFINED"
465
        }
466
        "Entry"
467
        {
468
        "MsmKey" = "8:_E5247C57FCF8FDC4526119494C9CA91D"
469
        "OwnerKey" = "8:_379682952A41C4DD701D113A41CD0ACC"
470
        "MsmSig" = "8:_UNDEFINED"
471
        }
472
        "Entry"
473
        {
474
        "MsmKey" = "8:_E573D8AD1AAEB39255958325DA5EDBD5"
475
        "OwnerKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE"
476
        "MsmSig" = "8:_UNDEFINED"
477
        }
478
        "Entry"
479
        {
480
        "MsmKey" = "8:_F65AE860659D453AAFD4D6F068DAC541"
481
        "OwnerKey" = "8:_UNDEFINED"
482
        "MsmSig" = "8:_UNDEFINED"
483
        }
484
        "Entry"
485
        {
486
        "MsmKey" = "8:_UNDEFINED"
487
        "OwnerKey" = "8:_BAA515E0FCDE402CBF2A6FF3D94A0B83"
488
        "MsmSig" = "8:_UNDEFINED"
489
        }
490
        "Entry"
491
        {
492
        "MsmKey" = "8:_UNDEFINED"
493
        "OwnerKey" = "8:_F65AE860659D453AAFD4D6F068DAC541"
494
        "MsmSig" = "8:_UNDEFINED"
495
        }
496
        "Entry"
497
        {
498
        "MsmKey" = "8:_UNDEFINED"
499
        "OwnerKey" = "8:_CE1C7673CEC14F70AFCF2B48FF8B3D37"
500
        "MsmSig" = "8:_UNDEFINED"
501
        }
502
        "Entry"
503
        {
504
        "MsmKey" = "8:_UNDEFINED"
505
        "OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A"
506
        "MsmSig" = "8:_UNDEFINED"
507
        }
508
        "Entry"
509
        {
510
        "MsmKey" = "8:_UNDEFINED"
511
        "OwnerKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE"
512
        "MsmSig" = "8:_UNDEFINED"
513
        }
514
        "Entry"
515
        {
516
        "MsmKey" = "8:_UNDEFINED"
517
        "OwnerKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA"
518
        "MsmSig" = "8:_UNDEFINED"
519
        }
520
        "Entry"
521
        {
522
        "MsmKey" = "8:_UNDEFINED"
523
        "OwnerKey" = "8:_0E4F95BDB07F23F411C53FB6C2E602F7"
524
        "MsmSig" = "8:_UNDEFINED"
525
        }
526
        "Entry"
527
        {
528
        "MsmKey" = "8:_UNDEFINED"
529
        "OwnerKey" = "8:_9F55CE39394926A083741C3E2824DE59"
530
        "MsmSig" = "8:_UNDEFINED"
531
        }
532
        "Entry"
533
        {
534
        "MsmKey" = "8:_UNDEFINED"
535
        "OwnerKey" = "8:_BBBEFA365EAA4B09B277CBDBED99E839"
536
        "MsmSig" = "8:_UNDEFINED"
537
        }
538
        "Entry"
539
        {
540
        "MsmKey" = "8:_UNDEFINED"
541
        "OwnerKey" = "8:_A2F4B8CF23FA43E69AF60DA69D47AA18"
542
        "MsmSig" = "8:_UNDEFINED"
543
        }
544
        "Entry"
545
        {
546
        "MsmKey" = "8:_UNDEFINED"
547
        "OwnerKey" = "8:_9419C61DF5F3441099A56E07565699F0"
548
        "MsmSig" = "8:_UNDEFINED"
549
        }
550
        "Entry"
551
        {
552
        "MsmKey" = "8:_UNDEFINED"
553
        "OwnerKey" = "8:_74535AE0FDD2421E81F24E0DB0554D26"
554
        "MsmSig" = "8:_UNDEFINED"
555
        }
556
        "Entry"
557
        {
558
        "MsmKey" = "8:_UNDEFINED"
559
        "OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80"
560
        "MsmSig" = "8:_UNDEFINED"
561
        }
562
        "Entry"
563
        {
564
        "MsmKey" = "8:_UNDEFINED"
565
        "OwnerKey" = "8:_8B189FCC1135DE71AFEBE665EBC98E1E"
566
        "MsmSig" = "8:_UNDEFINED"
567
        }
568
        "Entry"
569
        {
570
        "MsmKey" = "8:_UNDEFINED"
571
        "OwnerKey" = "8:_46914103D6A9E95AD780FA7F8D2149CA"
572
        "MsmSig" = "8:_UNDEFINED"
573
        }
574
        "Entry"
575
        {
576
        "MsmKey" = "8:_UNDEFINED"
577
        "OwnerKey" = "8:_ACC23150A2A1275D34D53AA04F5D868E"
578
        "MsmSig" = "8:_UNDEFINED"
579
        }
580
        "Entry"
581
        {
582
        "MsmKey" = "8:_UNDEFINED"
583
        "OwnerKey" = "8:_D27724C0B9E9EA480E1B445116EB2A8B"
584
        "MsmSig" = "8:_UNDEFINED"
585
        }
586
        "Entry"
587
        {
588
        "MsmKey" = "8:_UNDEFINED"
589
        "OwnerKey" = "8:_C7FAC6DF0866992BDABC6B70456C92F1"
590
        "MsmSig" = "8:_UNDEFINED"
591
        }
592
        "Entry"
593
        {
594
        "MsmKey" = "8:_UNDEFINED"
595
        "OwnerKey" = "8:_4414524BD941C2AB1F7C50E315B4C9EF"
596
        "MsmSig" = "8:_UNDEFINED"
597
        }
598
        "Entry"
599
        {
600
        "MsmKey" = "8:_UNDEFINED"
601
        "OwnerKey" = "8:_2837CB1EABE794B2B8C0028FDCFEA1C0"
602
        "MsmSig" = "8:_UNDEFINED"
603
        }
604
        "Entry"
605
        {
606
        "MsmKey" = "8:_UNDEFINED"
607
        "OwnerKey" = "8:_71AB7BB89699C43F04EFBBD41DFF976E"
608
        "MsmSig" = "8:_UNDEFINED"
609
        }
610
        "Entry"
611
        {
612
        "MsmKey" = "8:_UNDEFINED"
613
        "OwnerKey" = "8:_75D885F375DFDB481975C88F857E2ACF"
614
        "MsmSig" = "8:_UNDEFINED"
615
        }
616
        "Entry"
617
        {
618
        "MsmKey" = "8:_UNDEFINED"
619
        "OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3"
620
        "MsmSig" = "8:_UNDEFINED"
621
        }
622
        "Entry"
623
        {
624
        "MsmKey" = "8:_UNDEFINED"
625
        "OwnerKey" = "8:_476D990A74530772679162FBBFE0FCF4"
626
        "MsmSig" = "8:_UNDEFINED"
627
        }
628
        "Entry"
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff