#
creaImageIOGimmick
- creaImageIOSynchronizer
+ creaImageIOSynchron
creaImageIOTimestampDatabaseHandler
# Abstract views
CreateUserSettingsDirectory();
// Sets the current directory to the home dir
mCurrentDirectory = GetHomeDirectory();
- mSynchronizer=0;
+ mSynchronizer= new Synchronizer(GetUserSettingsDirectory());
std::string dbpath = GetLocalDatabasePath();
// Create or open local database
mImageAdder.SetTreeHandler(GetTreeHandler(d));
mImageAdder.SetTimestampHandler(mTimestampDatabase);
+ mImageAdder.SetSynchronizer(mSynchronizer);
mImageAdder.AddFiles(filenames);
-
+
}
//========================================================================
TreeHandler * handler=GetTreeHandler(d);
mImageAdder.SetTreeHandler(handler);
mImageAdder.SetTimestampHandler(mTimestampDatabase);
- mImageAdder.AddDirectory(f,recurse);
- //Synchronize(true, handler);
-
+ mImageAdder.SetSynchronizer(mSynchronizer);
+ mImageAdder.AddDirectory(f,recurse);
}
//========================================================================
//========================================================================
-
- void Gimmick::Synchronize(bool update, TreeHandler* handler)
+ void Gimmick::RemoveFile(const std::string& d,
+ const tree::Node* & node)
{
- GimmickMessage(4,"Synchronizing. Update:"<<update<<std::endl);
- if(mSynchronizer==0)
- {
- mSynchronizer=new Synchronizer(handler);
- }
- else
- {
- mSynchronizer->SetTreeHandler(handler);
- }
- mSynchronizer->Synchronize(update);
+ mImageAdder.SetSynchronizer(mSynchronizer);
+ mTimestampDatabase->RemoveNode("PATH",node);
+ mImageAdder.RemoveFile(node);
+ }
+ //========================================================================
+ //========================================================================
+
+ std::string Gimmick::Synchronize(bool repair, bool checkAttributes)
+ {
+ TreeHandler * handler=GetTreeHandler("Local database");
+ mImageAdder.SetTreeHandler(handler);
+ mImageAdder.SetTimestampHandler(mTimestampDatabase);
+ mImageAdder.SetSynchronizer(mSynchronizer);
+ return mImageAdder.Synchronize(repair, checkAttributes);
}
//========================================================================
#include <creaImageIOSQLiteTreeHandler.h>
#include <creaImageIOTreeHandlerImageAdder.h>
#include <creaImageIOTimestampDatabaseHandler.h>
-#include <creaImageIOSynchronizer.h>
+#include <creaImageIOSynchron.h>
namespace creaImageIO
{
void AddDir(const std::string& handler, const std::string& path,
bool recurse);
+ /// Removes a file from the given TreeHandler
+ void RemoveFile(const std::string& d,
+ const tree::Node* & filename);
+
///Synchronizes the loaded data with the database. If remove is true the database will be updated, otherwise
///only a warning sign will be issued
- void Synchronize(bool update, TreeHandler* handler);
+ std::string Synchronize(bool repair, bool checkAttributes);
/// Prints the tree handled by the handler
void Print(const std::string& handler);
i!= mGimmick->GetTreeHandlerMap().end();
++i)
{
- this->CreateTreeView(i->second, mGimmick->GetTimestampDatabase());
+ this->CreateTreeView(i->second);
}
}
/// Create a tree view with a given name
void GimmickView::CreateSingleTreeView(std::string &i_name)
{
- this->CreateTreeView(mGimmick->GetTreeHandlerMap()[i_name],
- mGimmick->GetTimestampDatabase());
+ this->CreateTreeView(mGimmick->GetTreeHandlerMap()[i_name]);
}
virtual void ClearSelection()
{ GimmickError("INTERNAL ERROR : ClearSelection not implemented"); }
+
+ ///Adds a file to ignore
+ virtual void AddIgnoreFile(const tree::Node* & toRemove)
+ { GimmickError("INTERNAL ERROR : AddIgnoreFile not implemented"); }
///Validates the dimension compliance of the images with the maximum and minimum given, and between their sizes
void CreateSingleTreeView(std::string &i_name);
/// Create the tree view for TreeHandler provided
- virtual void CreateTreeView( TreeHandler*, TimestampDatabaseHandler* )
+ virtual void CreateTreeView( TreeHandler* )
{ GimmickError("INTERNAL ERROR : CreateTreeView not implemented"); }
/// Updates the TreeView of given name from level l to bottom
// std::cout << "DELETE OK"<<std::endl;
return true;
}
-
- //========================================================================
-
-
//=====================================================================
--- /dev/null
+#include <creaImageIOSynchron.h>
+#include <creaImageIOSystem.h>
+#include <boost/filesystem.hpp>
+
+namespace fs = boost::filesystem;
+
+//=====================================================================
+
+
+namespace creaImageIO
+{
+
+ //=====================================================================
+ #define QUERYSYNCDB(QUER,RES) \
+ try \
+ { \
+ RES = mDB->execQuery(QUER.c_str()); \
+ } \
+ catch (CppSQLite3Exception& e) \
+ { \
+ GimmickError("SQLite query '"<<QUER<<"' Error : " \
+ << e.errorCode() << ":" \
+ << e.errorMessage() ); \
+ }
+ //=====================================================================
+ #define UPDATESYNCDB(UP) \
+ try \
+ { \
+ mDB->execDML(UP.c_str()); \
+ } \
+ catch (CppSQLite3Exception& e) \
+ { \
+ GimmickError("SQLite update '"<<UP<<"' Error : " \
+ << e.errorCode() << ":" \
+ << e.errorMessage() ); \
+ }
+ //=====================================================================
+
+ Synchronizer::Synchronizer(const std::string& path)
+ {
+ pathDB = path + "maintenance_database.db3";
+ mDB = new CppSQLite3DB;
+ Initialize();
+ }
+
+ //=====================================================================
+ Synchronizer::~Synchronizer()
+ {
+
+ }
+
+ //=====================================================================
+ void Synchronizer::Initialize()
+ {
+ if (!fs::exists(pathDB))
+ {
+ CreateDB();
+ }
+
+ // OPENING
+ else
+ {
+ try
+ {
+ mDB->open(pathDB.c_str());
+ }
+ catch (CppSQLite3Exception& e)
+ {
+ GimmickError("Opening '"<<pathDB<<"' : "
+ << e.errorCode() << ":"
+ << e.errorMessage());
+ }
+ }
+ // get the ADD operations List
+ UpdateAddList();
+ }
+
+ //=====================================================================
+ void Synchronizer::CreateDB()
+ {
+ mDB->open(pathDB.c_str());
+ // CREATING TABLES
+ std::string command;
+ command = "CREATE TABLE ";
+ command += "ADD_OPS";
+ command += "\n(\nADD_KEY INTEGER PRIMARY KEY";
+ command += ",\nPATH text";
+ command += ",\nRECURSIVE boolean";
+ command += ",\nFILES_ADDED int";
+ command += "\n)";
+ UPDATESYNCDB(command);
+
+ command = "CREATE TABLE ";
+ command += "IGNORED_FILES";
+ command += "\n(\nID INTEGER PRIMARY KEY";
+ command += ",\nADD_KEY integer";
+ command += ",\nPATH text";
+ command += ",\nREMOVE boolean";
+ command += ",\nTIME datetext";
+ command += "\n)";
+ UPDATESYNCDB(command);
+ }
+
+ //=====================================================================
+ void Synchronizer::CleanName(std::string& str) const
+ {
+ size_t pos;
+ do
+ {
+ pos = str.find('\\');
+ if (pos!=-1)
+ {
+ str.replace(pos, 1, "/");
+ }
+ }
+ while (pos!=-1);
+ }
+
+ //=====================================================================
+ void Synchronizer::GetFileList(std::vector<AddList> & list)
+ {
+ CleanList();
+ list=mAddList;
+ }
+
+ //=====================================================================
+ void Synchronizer::GetIgnoredFiles(const std::string& key, std::vector<std::string> &ignoreList)
+ {
+ ignoreList=GetIgnoreList(key);
+ }
+
+ //=====================================================================
+ void Synchronizer::UpdateAddList()
+ {
+ std::string query = "SELECT * FROM ADD_OPS";
+ CppSQLite3Query res;
+ QUERYSYNCDB(query, res);
+ while (!res.eof())
+ {
+ AddList temp = AddList(res);
+ mAddList.push_back(temp);
+ res.nextRow();
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // remove an entry of the DB
+ //@param i_table : table where do the remove
+ // @param i_key : the add_key reference (one entry to remove for ADD_OP table, many for IGNORED_FILES table
+ //@result : -
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ void Synchronizer::RemoveEntry(const std::string i_table, const std::string i_key)
+ {
+ std::string query = "DELETE FROM " + i_table + " WHERE ADD_KEY = '" + i_key +"'";
+ UPDATESYNCDB(query);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // clean DataBase if an operation has no child anymore
+ // @result : -
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ void Synchronizer::CleanList()
+ {
+ mAddList.clear();
+ UpdateAddList();
+ std::vector<AddList>::iterator it_add = mAddList.begin();
+ for(;it_add <mAddList.end(); ++it_add)
+ {
+ if(it_add->nbFiles == "0")
+ {
+ RemoveEntry("ADD_OPS", it_add->key);
+ RemoveEntry("IGNORED_FILES", it_add->key);
+
+ }
+ }
+ mAddList.clear();
+ UpdateAddList();
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // Inserts a new add operation in the database
+ // @param path: the path of the directory that was added
+ // @param recursive: shows if the action was called recursively or not
+ // @param nChildren: the number of files affected by the operation
+ // @result : The operation has been added
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ void Synchronizer::InsertAddOp(const std::string& path, const std::string& recursive, const std::string& nChildren)
+ {
+ std::string insert;
+ std::string pat=path.c_str();
+ CleanName(pat);
+ insert="INSERT INTO ADD_OPS (PATH,RECURSIVE,FILES_ADDED) VALUES('";
+ insert+=pat+"','";
+ insert+=recursive+"',";
+ insert+=nChildren+");";
+ UPDATESYNCDB(insert);
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // Inserts a new ignored file in the database
+ // @param add_key: the key of the add_op to which it corresponds
+ // @param path: the path of the directory that was added
+ // @param remove: shows if the file was removed or not
+ // @param time: the time in which the file was removed
+ // @result : The file has been inserted
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+
+ void Synchronizer::InsertIgnoreFile(const std::string& addKey, const std::string& path, const std::string& remove, const std::string& time)
+ {
+ std::string pat=path.c_str();
+ CleanName(pat);
+ std::string id=GetAttribute("ID","IGNORED_FILES","PATH",pat);
+ if(id.compare("")==0)
+ {
+ std::string insert;
+ insert="INSERT INTO IGNORED_FILES (ADD_KEY,PATH,REMOVE,TIME) VALUES('";
+ insert+=addKey+"','";
+ insert+=pat+"','";
+ insert+=remove+"',";
+ insert+=time+");";
+ UPDATESYNCDB(insert);
+ }
+ else
+ {
+ //Gets the add key
+ std::string ak=GetAttribute("ADD_KEY","IGNORED_FILES","ID",id);
+ //Sets the new add key attribute for the file
+ SetAttribute("ADD_KEY","IGNORED_FILES",addKey,"ID", id);
+ //Sets the new remove attribute for the file
+ SetAttribute("REMOVE","IGNORED_FILES",remove,"ID", id);
+ //Sets the new time attribute for the file
+ SetAttribute("TIME","IGNORED_FILES",time,"ID", id);
+ }
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // get the files name to ignore for a add operation synchronization
+ // @param : the add key
+ //@result : list (path) of ignore files
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ std::vector<std::string> Synchronizer::GetIgnoreList(const std::string &i_key)
+ {
+ mIgnoreList.clear();
+ std::vector<std::string> i_names;
+ std::string query = "SELECT * FROM IGNORED_FILES WHERE ADD_KEY = ";
+ query+=i_key;
+ CppSQLite3Query res;
+ QUERYSYNCDB(query, res);
+ while (!res.eof())
+ {
+ RemoveList temp = RemoveList(res);
+ if(temp.remove.compare("0")==0)
+ {
+ mIgnoreList.push_back(temp);
+ }
+ res.nextRow();
+ }
+ std::vector<RemoveList>::iterator it;
+
+ for(it = mIgnoreList.begin();it != mIgnoreList.end(); ++it)
+ {
+ i_names.push_back((*it).path);
+ }
+ return i_names;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // Gets the required attribute in the required table
+ // @param attribute: the attribute to look for
+ // @param table: the table to look in
+ // @param searchParam: the search parameter
+ // @param searchValue: the search value
+ // @result : required attribute
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ std::string Synchronizer::GetAttribute(const std::string& attribute,
+ const std::string& table,
+ const std::string& searchParam,
+ const std::string& searchValue)
+ {
+ std::stringstream query;
+ std::string result;
+ std::string sVal=searchValue.c_str();
+ CleanName(sVal);
+ query<<"SELECT "<<attribute<<" FROM "<<table<<" WHERE "<<searchParam<<" = '"<<sVal<<"';";
+ CppSQLite3Query res;
+ QUERYSYNCDB(query.str(), res);
+ while (!res.eof())
+ {
+ result=res.getStringField(0);
+ res.nextRow();
+ }
+ return result;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // Sets the attribute value in the required table and column
+ // @param attribute: the attribute to look for
+ // @param table: the table to look in
+ // @param value: the value to set
+ // @param searchParam: the search parameter
+ // @param searchValue: the search value
+ // @result : attribute value changed
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ void Synchronizer::SetAttribute(const std::string& attribute,
+ const std::string& table,
+ const std::string& value,
+ const std::string& searchParam,
+ const std::string& searchValue)
+ {
+ std::string val=value.c_str();
+ std::string sVal=searchValue.c_str();
+ CleanName(val);
+ CleanName(sVal);
+ std::string sql = "UPDATE ";
+ sql+=table;
+ sql+=" SET ";
+ sql += attribute;
+ sql += " = '";
+ sql += val;
+ sql += "' WHERE ";
+ sql += searchParam;
+ sql += " = '";
+ sql += sVal;
+ sql += "'";
+ UPDATESYNCDB(sql);
+ }
+}
\ No newline at end of file
--- /dev/null
+#ifndef __creaImageIOSynchron_h_INCLUDED__
+#define __creaImageIOSynchron_h_INCLUDED__
+
+#include <string>
+#include <map>
+#include <iostream>
+#include <vector>
+#include "CppSQLite3.h"
+
+namespace creaImageIO
+{
+ using namespace std;
+ //================================================================================================================
+ class AddList
+ {
+ public :
+ std::string key;
+ std::string path;
+ std::string recursive;
+ std::string nbFiles;
+ AddList(CppSQLite3Query& res):
+ key(res.getStringField(0)),
+ path(res.getStringField(1)),
+ recursive(res.getStringField(2)),
+ nbFiles(res.getStringField(3))
+ {}
+ };
+ //================================================================================================================
+
+ //================================================================================================================
+ class RemoveList
+ {
+ public :
+ std::string key;
+ std::string path;
+ std::string remove;
+ std::string time;
+
+ RemoveList(CppSQLite3Query& res):
+ key(res.getStringField(1)),
+ path(res.getStringField(2)),
+ remove(res.getStringField(3)),
+ time(res.getStringField(4))
+ {}
+ };
+ //================================================================================================================
+
+ //================================================================================================================
+ class Synchronizer
+ {
+ public:
+ Synchronizer(const std::string& path);
+ virtual ~Synchronizer();
+ void Initialize();
+ void InsertAddOp(const std::string& path,
+ const std::string& recursive,
+ const std::string& nChildren);
+ void InsertIgnoreFile(const std::string& addKey,
+ const std::string& path,
+ const std::string& remove,
+ const std::string& time);
+ void RemoveEntry(const std::string i_table, const std::string i_key);
+ void GetFileList(std::vector<AddList>& files);
+ void GetIgnoredFiles(const std::string& key, std::vector<std::string> &ignoreList);
+ std::string GetAttribute(const std::string& attribute,
+ const std::string& table,
+ const std::string& searchParam,
+ const std::string& searchValue);
+ void SetAttribute(const std::string& attribute,
+ const std::string& table,
+ const std::string& value,
+ const std::string& searchParam,
+ const std::string& searchValue);
+ std::vector<AddList> mAddList;
+ std::vector<RemoveList> mIgnoreList;
+ private :
+
+ /// The DB
+ CppSQLite3DB* mDB;
+ std::string pathDB;
+ void CreateDB();
+ void UpdateAddList();
+ void CleanList();
+ void CleanName(std::string& str) const;
+
+ std::vector<std::string> GetIgnoreList(const std::string &i_key);
+
+ };
+ //================================================================================================================
+
+
+}
+// EOF
+#endif
\ No newline at end of file
}
//=====================================================================
- void TimestampDatabaseHandler::RemoveNode(const std::string& searchAtt, tree::Node* node)
+ void TimestampDatabaseHandler::RemoveNode(const std::string& searchAtt, const tree::Node* node)
{
int n=node->GetNumberOfChildren();
if(n>0)
const std::string& searchParam,
const std::string& searchValue);
///Removes the given node
- void RemoveNode(const std::string& searchAtt, tree::Node* node);
+ void RemoveNode(const std::string& searchAtt, const tree::Node* node);
///Removes the filename with the given pathname
void RemoveFile(const std::string& searchAtt, const std::string& searchVal);
///Cleans the path name
using boost::prior;
-//using namespace crea;
+using namespace crea;
namespace creaImageIO
{
void TreeHandlerImageAdder::AddFiles( const std::vector<std::string>& filenames)
{
mProgress.Reset();
-
+
unsigned int nbf = filenames.size();
std::vector<std::string>::const_iterator i;
for (i=filenames.begin();i!=filenames.end();++i)
if (IsHandledFile(*i))
{
mProgress.IncNumberHandledFiles();
+ mSynchronizer->InsertAddOp((*i),"0","1");
+ std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","ADD_OPS","PATH",(*i));
+ std::stringstream removedOn;
+ removedOn<<time(0);
+ mSynchronizer->InsertIgnoreFile(addKey,(*i),"0",removedOn.str());
AddFile(*i);
}
mProgressSignal(mProgress);
bool recurse)
{
mProgress.Reset();
- AddDirectoryRecursor( directory, recurse );
+ std::stringstream files;
+
+ std::stringstream rec;
+ rec<<recurse;
+ mSynchronizer->InsertAddOp(directory,rec.str(),"0");
+ std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","ADD_OPS","PATH",directory);
+ AddDirectoryRecursor( directory, recurse, addKey );
+
+ int nFiles=GetProgress().GetNumberAddedFiles();
+ files<<nFiles;
+ mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",files.str(),"ADD_KEY",addKey);
GimmickDebugMessage(3,mProgress<<std::endl);
}
}
//=====================================================================
+ void TreeHandlerImageAdder::RemoveFile( const tree::Node*& node)
+ {
+ int n=node->GetNumberOfChildren();
+ if(n>0)
+ {
+ RemoveFiles(node->GetChildrenList());
+ }
+ else
+ {
+ std::string path=node->GetAttribute("FullFileName");
+ //Gets the add key
+ std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","IGNORED_FILES","PATH",path);
+ //Gets the number of files added
+ int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",addKey)).c_str());
+ files=files-1;
+ std::stringstream out;
+ out<<files;
+ //Sets the new number of files
+ mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",addKey);
+ //Sets the file as removed
+ mSynchronizer->SetAttribute("REMOVE","IGNORED_FILES","1","PATH",path);
+ }
+ }
+
+ //=====================================================================
+
+ void TreeHandlerImageAdder::RemoveFiles(const std::vector<tree::Node*>& nodes)
+ {
+ std::vector<tree::Node*>::const_iterator it;
+ for(it=nodes.begin();it!=nodes.end();++it)
+ {
+ int n=(*it)->GetNumberOfChildren();
+ if(n>0)
+ {
+ RemoveFiles((*it)->GetChildrenList());
+ }
+ else
+ {
+ std::string path=(*it)->GetAttribute("FullFileName");
+ //Gets the add key
+ std::string addKey=mSynchronizer->GetAttribute("ADD_KEY","IGNORED_FILES","PATH",path);
+ //Gets the number of files added
+ int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",addKey)).c_str());
+ files=files-1;
+ std::stringstream out;
+ out<<files;
+ //Sets the new number of files
+ mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",addKey);
+ //Sets the file as removed
+ mSynchronizer->SetAttribute("REMOVE","IGNORED_FILES","1","PATH",path);
+ }
+
+ }
+ }
+
//=====================================================================
void TreeHandlerImageAdder::AddDirectoryRecursor(const std::string &dirpath,
- bool recursive)
+ bool recursive,
+ const std::string &addKey)
{
GimmickDebugMessage(4,"Scanning '"<<dirpath<<"'"<<std::endl);
mProgress.IncNumberScannedDirs();
{
if (recursive)
{
- AddDirectoryRecursor( itr->string(), recursive);
+ AddDirectoryRecursor( itr->string(), recursive, addKey);
}
}
else
AddFile( itr->string() );
mTreeHandler->GetTopLevelNodeId("FullFileName",itr->string(),parent_id);
mTimestampHandler->SetAttribute("TopLevelNodeId",parent_id,"PATH",itr->string());
+ std::stringstream removedOn;
+ removedOn<<time(0);
+ mSynchronizer->InsertIgnoreFile(addKey, itr->string(),"0",removedOn.str());
}
mProgressSignal(mProgress);
if (mProgress.GetStop())
}
//=======================================================================
+
+ //=======================================================================
+
+ void TreeHandlerImageAdder::CheckSyncDirectory(const std::string &dirpath,
+ bool recursive,
+ bool repair,
+ bool checkAttributes,
+ std::vector<std::string> &i_ignorefiles,
+ std::vector<std::string> & attsModified,
+ std::vector<std::string> & newfiles)
+ {
+ if ( !fs::exists( dirpath ) ) return;
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+
+ for ( fs::directory_iterator itr( dirpath ); itr != end_itr; ++itr )
+ {
+ // If is directory & recurse : do recurse
+ if ( fs::is_directory(itr->status()) )
+ {
+ if (recursive)
+ {
+ CheckSyncDirectory( itr->string(), recursive, repair, checkAttributes, i_ignorefiles, attsModified, newfiles);
+ }
+ }
+ else
+ {
+ if (IsHandledFile(itr->string()))
+ {
+ bool bfound = false;
+ for(std::vector<std::string>::iterator it_new = i_ignorefiles.begin(); it_new < i_ignorefiles.end(); ++it_new)
+ {
+ if((*it_new) == itr->string())
+ {
+ bfound = true;
+ //Additional checking of attributes
+ if(checkAttributes)
+ {
+ CheckAttributes(repair,(*it_new),attsModified);
+ }
+ i_ignorefiles.erase(it_new);
+ break;
+ }
+ }
+ if(!bfound && i_ignorefiles.size()>0 )
+ {
+ newfiles.push_back( itr->string() );
+ }
+ }
+ }
+ }
+ }
+
+ //=======================================================================
+
+ //=======================================================================
+
+ std::string TreeHandlerImageAdder::Synchronize(bool repair, bool checkAttributes)
+ {
+ std::vector<AddList> fileList;
+ std::vector<std::string> ignoreList;
+ std::vector<std::string> newFiles;
+ std::vector<std::string> attsModified;
+ std::stringstream mess;
+ std::vector<AddList>::iterator iter;
+
+ //Gets the list of added files
+ mSynchronizer->GetFileList(fileList);
+
+ std::vector<std::string>::iterator i;
+ //Actions to take if the user doesn't want to repair
+ if(!repair)
+ {
+ //Iterates to see if they are in sync
+ for(iter=fileList.begin();iter!=fileList.end();++iter)
+ {
+ mSynchronizer->GetIgnoredFiles((*iter).key,ignoreList);
+ bool rec=true;
+ if((*iter).recursive=="0"){rec=false;}
+ CheckSyncDirectory((*iter).path,rec,repair,checkAttributes,ignoreList,attsModified,newFiles);
+ }
+
+ //Add to message the result of new found files
+ mess<<"New Files Found: "<<newFiles.size()<<std::endl;
+ if(newFiles.size()>0)
+ {
+ mess<<"Filenames: "<<std::endl;
+ for(i=newFiles.begin();i!=newFiles.end();++i)
+ {
+ mess<<*i<<std::endl;
+ }
+ }
+
+ //Add to message the result of missing files
+ mess<<"Missing Files: "<<ignoreList.size()<<std::endl;
+ if(ignoreList.size()>0)
+ {
+ mess<<"Filenames: "<<std::endl;
+ for(i=ignoreList.begin();i!=ignoreList.end();++i)
+ {
+ mess<<*i<<std::endl;
+ }
+ }
+
+ //In the case that the user wants to check the attributes...
+ if(checkAttributes)
+ {
+ //... add to message the result of files that have been changed.
+ mess<<"Files with different attributes: "<<attsModified.size()<<std::endl;
+ if(attsModified.size()>0)
+ {
+ mess<<"Filenames: "<<std::endl;
+ for(i=attsModified.begin();i!=attsModified.end();++i)
+ {
+ mess<<*i<<std::endl;
+ }
+ }
+ }
+
+ }
+
+ //Actions to take if the user wants to repair
+ else
+ {
+ int nf=0;
+ //Iterates to see if they are in sync
+ for(iter=fileList.begin();iter!=fileList.end();++iter)
+ {
+ mSynchronizer->GetIgnoredFiles((*iter).key,ignoreList);
+ bool rec=true;
+ if((*iter).recursive=="0"){rec=false;}
+ CheckSyncDirectory((*iter).path,rec,repair,checkAttributes,ignoreList,attsModified,newFiles);
+
+ //For the new files, add them
+ for (i=newFiles.begin();i!=newFiles.end();++i)
+ {
+ mTimestampHandler->AddFile((*i), fs::last_write_time(*i), time(0));
+ if (IsHandledFile(*i))
+ {
+ std::stringstream removedOn;
+ removedOn<<time(0);
+ mSynchronizer->InsertIgnoreFile((*iter).key,(*i),"0",removedOn.str());
+ //Gets the number of files added
+ int files=atoi((mSynchronizer->GetAttribute("FILES_ADDED","ADD_OPS","ADD_KEY",(*iter).key)).c_str());
+ files=files+1;
+ std::stringstream out;
+ out<<files;
+ //Sets the new number of files
+ mSynchronizer->SetAttribute("FILES_ADDED","ADD_OPS",out.str(),"ADD_KEY",(*iter).key);
+ AddFile(*i);
+ }
+ }
+ nf+=newFiles.size();
+ newFiles.clear();
+
+ }
+ //Reports number of added files
+ mess<<"Files Added: "<<nf<<std::endl;
+
+ //Removes the necessary files and reports the results
+ if(ignoreList.size()>0)
+ {
+ tree::Node* node;
+ mTreeHandler->LoadChildren(NULL,4);
+ for(i=ignoreList.begin();i!=ignoreList.end();++i)
+ {
+ FindNode(mTreeHandler->GetTree().GetChildrenList()[0],3,"FullFileName",*i,node);
+ RemoveFile(node);
+ mTreeHandler->Remove(node);
+ }
+ }
+ mess<<"Files Removed: "<<ignoreList.size()<<std::endl;
+ //In the case that the user wants to check the attributes...
+ if(checkAttributes)
+ {
+ //... add to message the result of files that were modified.
+ mess<<"Files Modified: "<<attsModified.size()<<std::endl;
+ }
+ }
+ return mess.str();
+
+ }
+ //=======================================================================
+
+ void TreeHandlerImageAdder::CheckAttributes(bool repair, std::string& file, std::vector<std::string>& attsModified)
+ {
+ std::map< std::string, std::string> attr;
+ mTreeHandler->GetTree().GetDescriptor().BuildAttributeMap(attr);
+ mReader.ReadAttributes(file,attr);
+ tree::LevelDescriptor::AttributeDescriptorListType adl= mTreeHandler->GetTree().GetAttributeDescriptorList(mTreeHandler->GetTree().GetNumberOfLevels()-1);
+ tree::LevelDescriptor::AttributeDescriptorListType::const_iterator a;
+ for (a = adl.begin();a!=adl.end();++a)
+ {
+ std::string databaseVal;
+ mTreeHandler->GetAttribute("Image","FullFileName",file,a->GetKey(),databaseVal);
+ std::string fileVal=attr.find(a->GetKey())->second;
+ if ( a->GetFlags()==0 && databaseVal.compare(fileVal)!=0 )
+ {
+ if(repair)
+ {
+ mTreeHandler->SetAttribute("Image",a->GetKey(),fileVal,"FullFileName", file);
+ }
+ attsModified.push_back(file);
+ }
+
+ }
+
+ }
+
+ //=======================================================================
+
+
+ void TreeHandlerImageAdder::FindNode(tree::Node* parent, int level, const std::string& searchParam, const std::string& searchVal, tree::Node*& node)
+ {
+ if(level>1)
+ {
+ std::vector<tree::Node*>::iterator iter;
+ for(iter=parent->GetChildrenList().begin();iter!=parent->GetChildrenList().end();++iter)
+ {
+ FindNode(*iter,level-1,searchParam,searchVal,node);
+ }
+ }
+ else
+ {
+ if(parent->GetAttribute(searchParam).compare(searchVal)==0)
+ {
+ node=parent;
+ }
+
+ }
+ }
+
+ //=======================================================================
#include <creaImageIOTreeHandler.h>
#include <creaImageIOTimestampDatabaseHandler.h>
+#include <creaImageIOSynchron.h>
#include <creaImageIOImageReader.h>
#include <wx/wx.h>
#include <wx/progdlg.h>
+#include <creaWx.h>
// Signal/slot mechanism for progress events
#include <boost/signal.hpp>
#include <boost/bind.hpp>
class TreeHandlerImageAdder
{
+
public:
//====================================================================
/// Ctor
void SetTreeHandler(TreeHandler* tree) { mTreeHandler = tree;}
/// Sets the TimestampDatabaseHandler
void SetTimestampHandler(TimestampDatabaseHandler* tdh) { mTimestampHandler = tdh;}
+ /// Sets the synchronizer
+ void SetSynchronizer(Synchronizer* s){mSynchronizer=s;}
//====================================================================
//====================================================================
void AddFiles( const std::vector<std::string>& filename );
/// (Recursively) adds the files of a directory to the TreeHandler
void AddDirectory( const std::string& directory,
- bool recurse );
+ bool recurse);
+ /// Removes a file from the databases
+ void RemoveFile(const tree::Node*& node);
+ /// Removes files from the databases
+ void RemoveFiles(const std::vector<tree::Node*>& nodes);
+ /// Synchronizes the DB and disk by repeating the operations the user has done and returns a report
+ std::string Synchronize(bool repair, bool checkAttributes);
+ ///Recursively checks if the directory is synchronized and optionally the state of the attributes
+ void CheckSyncDirectory(const std::string &dirpath,
+ bool recursive,
+ bool repair,
+ bool checkAttributes,
+ std::vector<std::string> &i_ignorefiles,
+ std::vector<std::string> & attsModified,
+ std::vector<std::string> & newfiles);
+ ///Finds the node that matches the specified parameters
+ void FindNode(tree::Node* parent, int level,
+ const std::string& searchParam,
+ const std::string& searchVal,
+ tree::Node*& node);
+ ///Checks the attributes of the database against the ones in disk
+ void CheckAttributes(bool repair, std::string& file, std::vector<std::string>& attsModified);
+
//====================================================================
private:
/// Recursive method which does the main job for AddDirectory
void AddDirectoryRecursor( const std::string& directory,
- bool recurse );
+ bool recurse,
+ const std::string &addKey);
TreeHandler* mTreeHandler;
TimestampDatabaseHandler* mTimestampHandler;
+ Synchronizer* mSynchronizer;
ImageReader mReader;
Progress mProgress;
{
//=============================================================
- /// Ctor with parent Why does it enter once while charging?
+ /// Ctor with parent
Node::Node(Node* parent)
: mParent(parent),
mData(0),
namespace creaImageIO
{
// CTor
- TreeView::TreeView(TreeHandler* handler, TimestampDatabaseHandler* tdh, GimmickView* gimmick )
+ TreeView::TreeView(TreeHandler* handler, GimmickView* gimmick )
: mTreeHandler(handler),
- mTimestampDatabaseHandler (tdh),
mGimmickView(gimmick)
{
GimmickDebugMessage(1,"TreeView::TreeView"
{
public:
/// Ctor
- TreeView(TreeHandler*,TimestampDatabaseHandler*,GimmickView*);
+ TreeView(TreeHandler*,GimmickView*);
/// Virtual destructor
virtual ~TreeView();
virtual void ValidateSelectedImages()
{ GimmickError("INTERNAL ERROR : TreeView::ValidateSelected not overloaded");}
+ ///Returns the last selected level
+ virtual unsigned int GetLastSelectedLevel(){GimmickError("INTERNAL ERROR : TreeView::GetLastSelectedLevel not overloaded");}
+
///Returns the maximum number of levels
virtual int GetNumberOfLevels(){ GimmickError("INTERNAL ERROR : TreeView::GetLevels not overloaded"); }
///Gets the current selections filenames
protected:
TreeHandler* GetTreeHandler() { return mTreeHandler; }
- TimestampDatabaseHandler* GetTimestampDatabaseHandler() { return mTimestampDatabaseHandler; }
- GimmickView* GetGimmickView() { return mGimmickView; }
+ GimmickView* GetGimmickView() { return mGimmickView; }
private:
/// The TreeHandler with which it corresponds
TreeHandler* mTreeHandler;
- /// The Timestamp handler with which it corresponds
- TimestampDatabaseHandler* mTimestampDatabaseHandler;
- /// The GimmickView which holds the TreeView
+ /// The GimmickView which holds the TreeView
GimmickView* mGimmickView;
};
#include "icons/remove.xpm"
#include "icons/database-add.xpm"
#include "icons/help.xpm"
+#include "icons/synchronize.xpm"
#include <wx/imaglist.h>
+#include <wx/popupwin.h>
#include<boost/filesystem/operations.hpp>
namespace creaImageIO
TOOL_ADDDIR_ID = 2,
TOOL_REMOVE_ID = 3,
TOOL_ADDDATABASE_ID = 4,
- TOOL_HELP_ID = 5
+ TOOL_HELP_ID = 5,
+ TOOL_SYNCHRONIZE_ID = 6
};
//======================================================================
//================================================================
//
- const int icon_number = 7;
+ const int icon_number = 8;
// Icon ids
typedef enum
{
Icon_page_down,
Icon_remove,
Icon_database_add,
- Icon_help
+ Icon_help,
+ Icon_synchronize
}
icon_id;
//================================================================
mIcon->GetBitmap(Icon_help),
_T("Open help window")
);
+ mToolSynchronize = mToolBar->AddTool( TOOL_SYNCHRONIZE_ID,
+ _T("Synchronize"),
+ mIcon->GetBitmap(Icon_synchronize),
+ _T("Synchronizes the database with disk")
+ );
//const wxBitmap& bitmap1, const wxString& shortHelpString = "", wxItemKind kind = wxITEM_NORMAL)
mToolBar->Realize();
//======================================================================
/// Create the tree view for TreeHandler provided
- void WxGimmickView::CreateTreeView( TreeHandler* h, TimestampDatabaseHandler* tdh)
+ void WxGimmickView::CreateTreeView( TreeHandler* h)
{
std::string name(h->GetTree().GetAttribute("Name"));
GimmickMessage(2,"Creating the tree view for '"<<
name<<"'"<<std::endl);
// Create the WxTreeView
- WxTreeView* view = new WxTreeView(h,tdh,this,mNotebook,-1);
+ WxTreeView* view = new WxTreeView(h,this,mNotebook,-1);
// TO DO : TEST THAT A VIEW WITH SAME NAME IS NOT
// ALREADY IN THE MAP
void WxGimmickView::CreateIconList()
{
// Size of the icons;
- int size = 24;
+ int size = 16;
wxIcon icons[20];
// should correspond to Icon_xxx enum
icons[Icon_remove] = wxIcon(remove_xpm);
icons[Icon_database_add] = wxIcon(database_add_xpm);
icons[Icon_help] = wxIcon(help_xpm);
+ icons[Icon_synchronize] = wxIcon(synchronize_xpm);
// unsigned int NbIcons = 8;
// Make an image list containing small icons
if(sel.size()==0)
{
-
valid= ValidateSelected(NULL,
mSelectionMinDimension,
mSelectionMaxDimension );
//TODO Select current tree handler
wxBusyCursor busy;
GetTreeViewMap()["Local database"]->RemoveSelected();
-
ClearSelection();
}
//=================================================
+
+ //=================================================
+ void WxGimmickView::AddIgnoreFile(const tree::Node* & toRemove)
+ {
+ mGimmick->RemoveFile("Local database",toRemove);
+ GetTreeViewMap()["Local database"]->UpdateLevel(1);
+ }
+
+ //=================================================
+ void WxGimmickView::OnSynchronize(wxCommandEvent& event)
+ {
+ wxBusyCursor busy;
+ const wxString choices[] = { _T("Check database for file deletion or addition and give a report."),
+ _T("Check database for file deletion or addition and attribute change and give a report."),
+ _T("Repair database (removes deleted files and adds new files)."),
+ _T("Repair database (removes deleted files, adds new files and resets changed attributes).") } ;
+
+ wxSingleChoiceDialog dialog(this,
+ _T("Select one of the following synchronization actions:\n")
+ _T("Plase note that, due to the heavy amount of operations required, this action might take a while."),
+ _T("Synchronization Settings"),
+ WXSIZEOF(choices), choices);
+
+ //dialog.SetSelection(0);
+
+ if (dialog.ShowModal() == wxID_OK)
+ {
+ int sel=dialog.GetSelection();
+ bool repair=false;
+ bool checkAttributes=false;
+ if(sel==2 || sel==3){repair=true;}
+ if(sel==1 || sel==3){checkAttributes=true;}
+ std::string mess=mGimmick->Synchronize(repair, checkAttributes);
+ wxMessageBox(std2wx(mess),_T("Synchronization result"),wxOK,this);
+ GetTreeViewMap()["Local database"]->UpdateLevel(1);
+
+ }
+ }
+ //=================================================
+
//=================================================
/// AddProgress Gimmick callback
void WxGimmickView::OnAddProgress( Gimmick::AddProgress& p)
EVT_TOOL(TOOL_ADDFILES_ID, WxGimmickView::OnAddFiles)
EVT_TOOL(TOOL_ADDDIR_ID, WxGimmickView::OnAddDir)
EVT_TOOL(TOOL_REMOVE_ID, WxGimmickView::OnRemove)
+ EVT_TOOL(TOOL_SYNCHRONIZE_ID, WxGimmickView::OnSynchronize)
EVT_TOOL(TOOL_ADDDATABASE_ID, WxGimmickView::OnAddDB)
END_EVENT_TABLE()
//=================================================
bool isSelection, int selection, bool mProcess);
///Stops the player
void StopPlayer(){mViewer->StopPlayer();}
+ ///Adds a file to ignore
+ void AddIgnoreFile(const tree::Node* & toRemove);
///Resets the default image
void ClearSelection();
/// Create the tree view for TreeHandler provided
/// (overloaded from GimmickView)
- void CreateTreeView( TreeHandler*, TimestampDatabaseHandler* );
+ void CreateTreeView( TreeHandler* );
private:
wxToolBarToolBase* mToolRemove;
wxToolBarToolBase* mToolAddDatabase;
wxToolBarToolBase* mToolHelp;
+ wxToolBarToolBase* mToolSynchronize;
wxSplitterWindow* mSplitter;
wxPanel* mBottomPanel;
void OnAddDir(wxCommandEvent& event);
/// Callback for removing files
void OnRemove(wxCommandEvent& event);
+ /// Callback for removing files
+ void OnSynchronize(wxCommandEvent& event);
/// Display a message box with the last addition statistics
void DisplayAddSummary();
//=====================================================================
// CTor
WxTreeView::WxTreeView(TreeHandler* handler,
- TimestampDatabaseHandler* tdh,
GimmickView* gimmick,
wxWindow* parent,
const wxWindowID id)
: wxPanel(parent,id),
- TreeView(handler, tdh, gimmick)
+ TreeView(handler, gimmick)
{
GimmickDebugMessage(1,"WxTreeView::WxTreeView"
<<std::endl);
{
needRefresh=true;
}
- GetTimestampDatabaseHandler()->RemoveNode("PATH",(*i));
- GetTreeHandler()->Remove(*i);
+ tree::Node* n= (tree::Node*)(*i);
+ GetTreeHandler()->LoadChildren((*i),4);
+ GetGimmickView()->AddIgnoreFile(n);
+ GetTreeHandler()->Remove(*i);
}
if(needRefresh && mLastLevel>1)
{
public:
/// Ctor
- WxTreeView(TreeHandler*, TimestampDatabaseHandler*, GimmickView*,
+ WxTreeView(TreeHandler*, GimmickView*,
wxWindow* parent, const wxWindowID id);
/// Virtual destructor
virtual ~WxTreeView();
///Removes selected nodes on given level
virtual void RemoveSelected();
+ ///Returns the last selected level
+ virtual unsigned int GetLastSelectedLevel(){return mLastLevel;}
+
/// Callback for item selection
void OnItemSelected(wxListEvent& event);
--- /dev/null
+/* XPM */
+static char *synchronize_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"48 50 155 2",
+" c #2FBF25",
+". c #32BF28",
+"X c #37BF2D",
+"o c #38BF2E",
+"O c #39A631",
+"+ c #3ABF31",
+"@ c #3BBE32",
+"# c #41B339",
+"$ c #47B13F",
+"% c #42BF39",
+"& c #2BC81F",
+"* c #2AE01D",
+"= c #29E31C",
+"- c #2AE31C",
+"; c #2AE21D",
+": c #2CE21F",
+"> c #2BE41D",
+", c #2AE61C",
+"< c #2BE41E",
+"1 c #27E819",
+"2 c #26ED18",
+"3 c #28EB19",
+"4 c #28EC1A",
+"5 c #29ED1B",
+"6 c #2AED1B",
+"7 c #2AE81D",
+"8 c #2BEB1D",
+"9 c #2DE91F",
+"0 c #2CEA1E",
+"q c #2DEA1F",
+"w c #2AEF1C",
+"e c #2BEF1D",
+"r c #2CEF1D",
+"t c #2CED1E",
+"y c #2CEE1E",
+"u c #2DEE1F",
+"i c #25F116",
+"p c #25F616",
+"a c #25F716",
+"s c #26F616",
+"d c #25F815",
+"f c #25F915",
+"g c #25FA15",
+"h c #24FB15",
+"j c #25FB15",
+"k c #25F816",
+"l c #26F816",
+"z c #26F916",
+"x c #27F917",
+"c c #25FB16",
+"v c #26FA16",
+"b c #26FB16",
+"n c #26FA17",
+"m c #27FA17",
+"M c #26FB17",
+"N c #24FD14",
+"B c #24FC15",
+"V c #25FC15",
+"C c #24FD15",
+"Z c #25FD15",
+"A c #24FE14",
+"S c #24FF14",
+"D c #24FE15",
+"F c #25FD16",
+"G c #26FC16",
+"H c #27F318",
+"J c #27F419",
+"K c #28F019",
+"L c #28F119",
+"P c #29F01A",
+"I c #28F519",
+"U c #28F619",
+"Y c #28F719",
+"T c #29F51A",
+"R c #29F71A",
+"E c #2AF61B",
+"W c #2BF11D",
+"Q c #2DF01E",
+"! c #2BF41D",
+"~ c #2BF61D",
+"^ c #27FA18",
+"/ c #28F818",
+"( c #28F919",
+") c #28FA19",
+"_ c #2CC321",
+"` c #2DC122",
+"' c #2DC222",
+"] c #2FC424",
+"[ c #34C22A",
+"{ c #35C32A",
+"} c #37C12C",
+"| c #34CD29",
+" . c #35CD29",
+".. c #34CE29",
+"X. c #37C82C",
+"o. c #39CD2F",
+"O. c #2ED622",
+"+. c #2FD623",
+"@. c #2EDC21",
+"#. c #2EDE21",
+"$. c #31D625",
+"%. c #33D427",
+"&. c #30DB23",
+"*. c #31D824",
+"=. c #31DB24",
+"-. c #31DC24",
+";. c #31DF24",
+":. c #33DD26",
+">. c #33DD27",
+",. c #34DF27",
+"<. c #33D028",
+"1. c #34D028",
+"2. c #35D32A",
+"3. c #3AD02F",
+"4. c #39D22E",
+"5. c #38D52C",
+"6. c #36DF2A",
+"7. c #37DF2B",
+"8. c #3BDB2F",
+"9. c #3BCB30",
+"0. c #3CC932",
+"q. c #3BCE30",
+"w. c #3CCF32",
+"e. c #3FD434",
+"r. c #2EE021",
+"t. c #2FE222",
+"y. c #2DE420",
+"u. c #2DE620",
+"i. c #2DE720",
+"p. c #2EE721",
+"a. c #2FE522",
+"s. c #2DEA20",
+"d. c #30E023",
+"f. c #30E123",
+"g. c #31E024",
+"h. c #33E326",
+"j. c #31E823",
+"k. c #37E32A",
+"l. c #41C137",
+"z. c #41CB37",
+"x. c #41C038",
+"c. c #45C63C",
+"v. c #41D236",
+"b. c #42D637",
+"n. c #4BAD44",
+"m. c #50AD49",
+"M. c #4EB346",
+"N. c #49BB40",
+"B. c #4ABC41",
+"V. c #54B34D",
+"C. c #55B34E",
+"Z. c #52B94B",
+"A. c #5AB354",
+"S. c #699C65",
+"D. c None",
+/* pixels */
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.O D.D.S.A.A.A.A.V.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.e.e N S S S S O.. 4 S N N N S y v.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.8 N N S S S b ..D.D.D.o.N N N S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.@ h S S S S S Q D.D.D.D.D.D.D.S S S S S S b X D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.% S S S S S S S D.D.D.D.D.D.D.D.D.b S S S S S S { D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.b S S S S S S D.D.D.D.D.D.D.D.D.D.X.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.b S S S S S S *.D.D.D.D.D.D.D.D.D.D.D.f.S S S S S S Y D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.#.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.( S S S S S S $.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.S S S S S S S z.D.D.D.D.D.D.D.D.D.D.D.D.D.b.S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.- S S S S S S b D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.( S S S S S S 6.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.b S S S S S S 6.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.f.S S S S S S ^ D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.<.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S w.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.a.S S S S S S 0 D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.e S S S S S S a.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.S S S S S S S $.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.- S S S S S S Y D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D...s s b S S S S S S S b s s _ D.D.D.D.D.D.",
+"D.D.D.D.6.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.x.Y N N S S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.8 S S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.2 N S S S S S S b Z.D.D.D.D.D.D.D.D.",
+"D.D.D.D.;.S S S S S S 0 D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.f.S S S S N b D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.i S S S S S S -.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D...b S S b D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D., S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.y b D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.M.B.B.B.B.B.B.$ D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.V.s.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.b f s b b s d m.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.( S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.` S S S S S 5.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.$ S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.] b S S S S S S t.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.* S S S S S S S D.D.D.D.D.D.D.D.",
+"D.D.D.D.c.S S S S S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.6.S S S S S S b D.D.D.D.D.D.D.D.",
+"D.D.D.- b S S S S S S S S S S S 0.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.j.S S S S S S 4 D.D.D.D.D.D.D.D.",
+"D.D.D.` _ ` y S S S S S S b ` ` D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.Y S S S S S S #.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.4.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S { D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.N S S S S S S f.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.$.S S S S S S S D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.4 S S S S S S W D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.J S S S S S S : D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.e.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.~ S S S S S S k.D.D.D.D.D.D.D.D.D.D.D.D.D.D.a.S S S S S S y D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.v.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.S S S S S S S D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.y S S S S S S s.D.D.D.D.D.D.D.D.D.D.D.D.4 S S S S S S y D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.S S S S S S S 0.D.D.D.D.D.D.D.D.D.D.$.S S S S S S Y D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.@ S S S S S S b D.D.D.D.D.D.D.D.D.} S S S S S S S # D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.& S S S S S S ~ D.D.D.D.D.D.D.n.Y S S S S S S D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.% J S S S S S Y D.D.D.D.D.1.! S S S S S P D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.3 S S S S S N *.D.D.a.N N N S S S a.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.t.8.1 1 3 > ..} - ;.2.-.;.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.",
+"D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D."
+};