2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file task_manifest_file.cpp
18 * @author Pawel Sikorski (p.sikorski@samgsung.com)
25 #include <dpl/assert.h>
29 #include <shortcut/shortcut.h>
32 #include <widget_install/task_manifest_file.h>
33 #include <widget_install/job_widget_install.h>
34 #include <widget_install/widget_install_errors.h>
35 #include <widget_install/widget_install_context.h>
36 #include <dpl/wrt-dao-ro/global_config.h>
37 #include <dpl/log/log.h>
38 #include <dpl/file_input.h>
39 #include <dpl/file_output.h>
41 #include <dpl/exception.h>
42 #include <dpl/foreach.h>
43 #include <dpl/sstream.h>
44 #include <dpl/string.h>
45 #include <dpl/optional.h>
46 #include <dpl/utils/wrt_utility.h>
48 #include <libxml_utils.h>
49 #include <pkgmgr/pkgmgr_parser.h>
51 #define DEFAULT_ICON_NAME "icon.png"
53 using namespace WrtDB;
56 typedef std::map<DPL::String, DPL::String> LanguageTagMap;
58 LanguageTagMap getLanguageTagMap()
62 #define ADD(tag, l_tag) map.insert(std::make_pair(L ## # tag, L ## # l_tag));
63 #include "languages.def"
69 DPL::OptionalString getLangTag(const DPL::String& tag)
71 static LanguageTagMap TagsMap =
74 DPL::String langTag = tag;
76 LogDebug("Trying to map language tag: " << langTag);
77 size_t pos = langTag.find_first_of(L'_');
78 if (pos != DPL::String::npos) {
81 DPL::OptionalString ret;
83 LanguageTagMap::iterator it = TagsMap.find(langTag);
84 if (it != TagsMap.end()) {
87 LogDebug("Mapping IANA Language tag to language tag: " <<
88 langTag << " -> " << ret);
95 namespace WidgetInstall {
97 const char * TaskManifestFile::encoding = "UTF-8";
99 TaskManifestFile::TaskManifestFile(InstallerContext &inCont) :
100 DPL::TaskDecl<TaskManifestFile>(this),
103 if (false == m_context.existingWidgetInfo.isExist) {
104 AddStep(&TaskManifestFile::stepCopyIconFiles);
105 AddStep(&TaskManifestFile::stepCreateExecFile);
106 AddStep(&TaskManifestFile::stepGenerateManifest);
107 AddStep(&TaskManifestFile::stepParseManifest);
108 if (m_context.browserRequest) {
109 AddStep(&TaskManifestFile::stepCreateShortcut);
111 AddStep(&TaskManifestFile::stepFinalize);
113 // for widget update.
114 AddStep(&TaskManifestFile::stepBackupIconFiles);
115 AddStep(&TaskManifestFile::stepCopyIconFiles);
116 AddStep(&TaskManifestFile::stepGenerateManifest);
117 AddStep(&TaskManifestFile::stepParseUpgradedManifest);
118 AddStep(&TaskManifestFile::stepUpdateFinalize);
120 AddAbortStep(&TaskManifestFile::stepAbortIconFiles);
124 TaskManifestFile::~TaskManifestFile()
128 void TaskManifestFile::stepCreateExecFile()
130 //ln -s /usr/bin/wrt-client {widget-handle}
132 std::ostringstream real_path;
133 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
134 if (pkgname.IsNull()) {
135 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
138 real_path << GlobalConfig::GetUserInstalledWidgetPath() << "/";
139 real_path << pkgname << "/";
140 real_path << GlobalConfig::GetUserWidgetExecPath() << "/" <<
141 m_context.widgetHandle;
142 std::string clientExeStr = GlobalConfig::GetWrtClientExec();
144 LogInfo("link -s " << clientExeStr << " " << real_path.str());
145 symlink(clientExeStr.c_str(), real_path.str().c_str());
147 m_context.job->UpdateProgress(
148 InstallerContext::INSTALL_CREATE_EXECFILE,
149 "Widget execfile creation Finished");
152 void TaskManifestFile::stepCopyIconFiles()
154 LogDebug("CopyIconFiles");
156 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
157 if (pkgname.IsNull()) {
158 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
160 Assert(!!m_context.widgetHandle);
162 WidgetDAOReadOnly dao(*m_context.widgetHandle);
163 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
164 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
168 DPL::String i = it->widgetLocale;
169 DPL::OptionalString src;
172 if (icon->iconId == it->iconId) {
176 LogDebug("Icon for locale: " << i << "is : " << src);
178 std::ostringstream sourceFile;
179 std::ostringstream targetFile;
182 if (m_context.browserRequest) {
183 size_t pos = m_context.widgetSource.rfind("/");
184 sourceFile << m_context.widgetSource.substr(0, pos+1);
186 sourceFile << GlobalConfig::GetUserInstalledWidgetPath() << "/";
187 sourceFile << pkgname << "/";
188 sourceFile << GlobalConfig::GetWidgetSrcPath() << "/";
192 sourceFile << "locales/" << i << "/";
197 targetFile << GlobalConfig::GetUserWidgetDesktopIconPath() << "/";
198 targetFile << getIconTargetFilename(i);
200 if (m_context.browserRequest) {
201 m_context.installedIconPath = targetFile.str();
204 //Use WRT default (not from the widget) only if widget default (not
205 // localized) doesn't exist.
207 LogError("Using Default Icon for widget");
208 sourceFile << GlobalConfig::GetUserWidgetDefaultIconFile();
214 LogDebug("Copying icon: " << sourceFile.str() <<
215 " -> " << targetFile.str());
217 icon_list.push_back(targetFile.str());
221 DPL::FileInput input(sourceFile.str());
222 DPL::FileOutput output(targetFile.str());
223 DPL::Copy(&input, &output);
226 Catch(DPL::FileInput::Exception::Base)
228 // Error while opening or closing source file
229 //ReThrowMsg(InstallerException::CopyIconFailed, sourceFile.str());
231 "Copying widget's icon failed. Widget's icon will not be"\
232 "available from Main Screen");
235 Catch(DPL::FileOutput::Exception::Base)
237 // Error while opening or closing target file
238 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
240 "Copying widget's icon failed. Widget's icon will not be"\
241 "available from Main Screen");
244 Catch(DPL::CopyFailed)
246 // Error while copying
247 //ReThrowMsg(InstallerException::CopyIconFailed, targetFile.str());
249 "Copying widget's icon failed. Widget's icon will not be"\
250 "available from Main Screen");
254 m_context.job->UpdateProgress(
255 InstallerContext::INSTALL_COPY_ICONFILE,
256 "Widget iconfile copy Finished");
259 void TaskManifestFile::stepCreateShortcut()
261 LogInfo("create shortcut");
263 WidgetDAOReadOnly dao(*m_context.widgetHandle);
264 LanguageTagsList languageTags(dao.getLanguageTags());
265 DPL::OptionalString name;
266 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
268 FOREACH(i, languageTags)
270 name = dao.getLocalizedInfo(*i).name;
271 if (!name.IsNull()) {
272 LogInfo("found name: " << DPL::ToUTF8String(*name).c_str());
277 add_to_home_shortcut(DPL::ToUTF8String(*pkgname).c_str(),
278 DPL::ToUTF8String(*name).c_str(),
280 DPL::ToUTF8String(*name).c_str(),
281 m_context.installedIconPath.c_str(),
284 m_context.job->UpdateProgress(
285 InstallerContext::INSTALL_CREATE_SHORTCUT,
286 "shortcut creation Finished");
289 void TaskManifestFile::stepBackupIconFiles()
291 LogDebug("Backup Icon Files");
293 backup_dir << GlobalConfig::GetUserInstalledWidgetPath();
294 backup_dir << "/" << m_context.widgetConfig.pkgname;
295 backup_dir << "/" << "backup" << "/";
299 m_context.job->UpdateProgress(
300 InstallerContext::INSTALL_BACKUP_ICONFILE,
301 "New Widget icon file backup Finished");
304 void TaskManifestFile::stepAbortIconFiles()
306 LogDebug("Abrot Icon Files");
307 FOREACH(it, icon_list)
309 LogDebug("Remove Update Icon : " << (*it));
310 unlink((*it).c_str());
313 std::ostringstream b_icon_dir;
314 b_icon_dir << backup_dir.str() << "icons";
316 std::list<std::string> fileList;
317 getFileList(b_icon_dir.str().c_str(), fileList);
319 FOREACH(back_icon, fileList)
321 std::ostringstream res_file;
322 res_file << GlobalConfig::GetUserWidgetDesktopIconPath();
323 res_file << "/" << (*back_icon);
325 std::ostringstream backup_file;
326 backup_file << b_icon_dir.str() << "/" << (*back_icon);
330 DPL::FileInput input(backup_file.str());
331 DPL::FileOutput output(res_file.str());
332 DPL::Copy(&input, &output);
334 Catch(DPL::FileInput::Exception::Base)
336 LogError("Restoration icon File Failed." << backup_file.str()
337 << " to " << res_file.str());
340 Catch(DPL::FileOutput::Exception::Base)
342 LogError("Restoration icon File Failed." << backup_file.str()
343 << " to " << res_file.str());
345 Catch(DPL::CopyFailed)
347 LogError("Restoration icon File Failed." << backup_file.str()
348 << " to " << res_file.str());
353 void TaskManifestFile::stepUpdateFinalize()
355 LogDebug("Finished Update Desktopfile");
358 DPL::String TaskManifestFile::getIconTargetFilename(
359 const DPL::String& languageTag) const
361 DPL::OStringStream filename;
362 DPL::Optional<DPL::String> pkgname = m_context.widgetConfig.pkgname;
363 if (pkgname.IsNull()) {
364 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
367 filename << DPL::ToUTF8String(*pkgname).c_str();
369 if (!languageTag.empty()) {
370 DPL::OptionalString tag = getLangTag(languageTag); // translate en -> en_US etc
371 if (tag.IsNull()) { tag = languageTag; }
373 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
376 filename << L"." << languageTag;
378 filename << L"." << locale;
383 return filename.str();
386 void TaskManifestFile::stepFinalize()
388 LogInfo("Finished ManifestFile step");
391 void TaskManifestFile::saveLocalizedKey(std::ofstream &file,
392 const DPL::String& key,
393 const DPL::String& languageTag)
396 LocalizationUtils::BCP47LanguageTagToLocale(languageTag);
399 if (!locale.empty()) {
400 file << "[" << locale << "]";
405 void TaskManifestFile::updateAilInfo()
407 // Update ail for desktop
408 std::string cfgPkgname =
409 DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
410 const char* pkgname = cfgPkgname.c_str();
412 LogDebug("Update ail desktop : " << pkgname );
413 ail_appinfo_h ai = NULL;
416 ret = ail_package_get_appinfo(pkgname, &ai);
418 ail_package_destroy_appinfo(ai);
421 if (AIL_ERROR_NO_DATA == ret) {
422 if (ail_desktop_add(pkgname) < 0) {
423 LogDebug("Failed to add ail desktop : " << pkgname);
425 } else if (AIL_ERROR_OK == ret) {
426 if (ail_desktop_update(pkgname) < 0) {
427 LogDebug("Failed to update ail desktop : " << pkgname);
432 void TaskManifestFile::backupIconFiles()
434 LogInfo("Backup Icon Files");
436 std::ostringstream b_icon_dir;
437 b_icon_dir << backup_dir.str() << "icons";
439 LogDebug("Create icon backup folder : " << b_icon_dir.str());
440 _WrtMakeDir(b_icon_dir.str().c_str(), 0755, WRT_FILEUTILS_RECUR);
442 std::list<std::string> fileList;
443 getFileList(GlobalConfig::GetUserWidgetDesktopIconPath(), fileList);
444 std::string pkgname = DPL::ToUTF8String(*m_context.widgetConfig.pkgname);
446 FOREACH(it, fileList)
448 if (0 == (strncmp((*it).c_str(), pkgname.c_str(),
449 strlen(pkgname.c_str())))) {
450 std::ostringstream icon_file, backup_icon;
451 icon_file << GlobalConfig::GetUserWidgetDesktopIconPath();
452 icon_file << "/" << (*it);
454 backup_icon << b_icon_dir.str() << "/" << (*it);
456 LogDebug("Backup icon file " << icon_file.str() << " to " <<
460 DPL::FileInput input(icon_file.str());
461 DPL::FileOutput output(backup_icon.str());
462 DPL::Copy(&input, &output);
464 Catch(DPL::FileInput::Exception::Base)
466 LogError("Backup Desktop File Failed.");
467 ReThrowMsg(Exceptions::BackupFailed, icon_file.str());
470 Catch(DPL::FileOutput::Exception::Base)
472 LogError("Backup Desktop File Failed.");
473 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
475 Catch(DPL::CopyFailed)
477 LogError("Backup Desktop File Failed.");
478 ReThrowMsg(Exceptions::BackupFailed, backup_icon.str());
480 unlink((*it).c_str());
485 void TaskManifestFile::getFileList(const char* path,
486 std::list<std::string> &list)
488 DIR* dir = opendir(path);
490 LogError("icon directory doesn't exist");
491 ThrowMsg(Exceptions::InternalError, path);
494 struct dirent* d_ent;
496 if ((d_ent = readdir(dir))) {
497 if(strcmp(d_ent->d_name, ".") == 0 ||
498 strcmp(d_ent->d_name, "..") == 0) {
501 std::string file_name = d_ent->d_name;
502 list.push_back(file_name);
507 void TaskManifestFile::stepGenerateManifest()
509 DPL::String pkgname = *m_context.widgetConfig.pkgname;
510 manifest_name = pkgname + L".xml";
511 manifest_file += L"/tmp/" + manifest_name;
513 //libxml - init and check
514 LibxmlSingleton::Instance().init();
516 writeManifest(manifest_file);
520 m_context.job->UpdateProgress(
521 InstallerContext::INSTALL_CREATE_MANIFEST,
522 "Widget Manifest Creation Finished");
525 void TaskManifestFile::stepParseManifest()
527 int code = pkgmgr_parser_parse_manifest_for_installation(
528 DPL::ToUTF8String(manifest_file).c_str(), NULL);
532 LogError("Manifest parser error: " << code);
533 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
536 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
539 m_context.job->UpdateProgress(
540 InstallerContext::INSTALL_CREATE_MANIFEST,
541 "Widget Manifest Parsing Finished");
542 LogDebug("Manifest parsed");
545 void TaskManifestFile::stepParseUpgradedManifest()
547 int code = pkgmgr_parser_parse_manifest_for_upgrade(
548 DPL::ToUTF8String(manifest_file).c_str(), NULL);
552 LogError("Manifest parser error: " << code);
553 ThrowMsg(ManifestParsingError, "Parser returncode: " << code);
556 // TODO : It will be removed. AIL update is temporary code request by pkgmgr team.
559 m_context.job->UpdateProgress(
560 InstallerContext::INSTALL_CREATE_MANIFEST,
561 "Widget Manifest Parsing Finished");
562 LogDebug("Manifest parsed");
565 void TaskManifestFile::validateManifest()
567 int code = pkgmgr_parser_check_manifest_validation(
568 DPL::ToUTF8String(manifest_name).c_str());
572 LogError("Manifest validation error");
573 //TODO: manifest files are not yet validating properly because of href
574 // attribute in author element (incompatible types in W3C spec. and
576 //ThrowMsg(ManifestValidationError, "Validation returncode: " << code);
579 m_context.job->UpdateProgress(
580 InstallerContext::INSTALL_CREATE_MANIFEST,
581 "Widget Manifest Validation Finished");
582 LogDebug("Manifest validated");
585 void TaskManifestFile::commitManifest()
587 LogDebug("Commiting manifest file : " << manifest_file);
589 std::ostringstream destFile;
590 destFile << "/opt/share/packages" << "/"; //TODO constant with path
591 destFile << DPL::ToUTF8String(manifest_name);
592 LogInfo("cp " << manifest_file << " " << destFile.str());
594 DPL::FileInput input(DPL::ToUTF8String(manifest_file));
595 DPL::FileOutput output(destFile.str());
596 DPL::Copy(&input, &output);
597 LogDebug("Manifest writen to: " << destFile.str());
600 unlink((DPL::ToUTF8String(manifest_file)).c_str());
601 manifest_file = DPL::FromUTF8String(destFile.str().c_str());
604 void TaskManifestFile::writeManifest(const DPL::String & path)
606 LogDebug("Generating manifest file : " << path);
610 setWidgetExecPath(uiApp);
611 setWidgetName(manifest, uiApp);
612 setWidgetIcons(uiApp);
613 setWidgetManifest(manifest);
614 setWidgetOtherInfo(uiApp);
615 setAppServiceInfo(uiApp);
617 manifest.addUiApplication(uiApp);
618 manifest.generate(path);
619 LogDebug("Manifest file serialized");
622 void TaskManifestFile::setWidgetExecPath(UiApplication & uiApp)
624 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
625 if (pkgname.IsNull()) {
626 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
629 std::ostringstream path;
630 path << GlobalConfig::GetUserInstalledWidgetPath() << "/" << *pkgname << "/";
631 path << GlobalConfig::GetUserWidgetExecPath() << "/" << *m_context.widgetHandle;
632 uiApp.setExec(DPL::FromASCIIString(path.str()));
635 void TaskManifestFile::setWidgetName(Manifest & manifest, UiApplication & uiApp)
637 Assert(!!m_context.widgetHandle);
638 WidgetDAOReadOnly dao(*m_context.widgetHandle);
639 LanguageTagsList languageTags(dao.getLanguageTags());
640 bool defaultNameSaved = false;
643 FOREACH(i, languageTags)
645 DPL::OptionalString tag = getLangTag(*i); // translate en -> en_US etc
650 DPL::OptionalString name = dao.getLocalizedInfo(*i).name;
651 generateWidgetName(manifest, uiApp, tag, name, defaultNameSaved);
653 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
654 if (!!defaultLocale && !defaultNameSaved)
656 DPL::OptionalString name = dao.getLocalizedInfo(*defaultLocale).name;
657 generateWidgetName(manifest, uiApp, DPL::OptionalString::Null, name, defaultNameSaved);
661 if(!!m_context.widgetConfig.pkgname)
663 pkgname = *m_context.widgetConfig.pkgname;
664 uiApp.setAppid(pkgname);
668 if(!!m_context.widgetConfig.guid) {
669 uiApp.setExtraid(*m_context.widgetConfig.guid);
671 if(!pkgname.empty()) {
672 uiApp.setExtraid(DPL::String(L"http://") + pkgname);
677 uiApp.setType(DPL::FromASCIIString("webapp"));
678 manifest.setType(L"wgt");
679 uiApp.setTaskmanage(true);
682 void TaskManifestFile::generateWidgetName(Manifest & manifest, UiApplication &uiApp, const DPL::OptionalString& tag, DPL::OptionalString name, bool & defaultNameSaved)
688 LocalizationUtils::BCP47LanguageTagToLocale(*tag);
690 if (!locale.empty()) {
691 uiApp.addLabel(LabelType(*name,*tag));
695 uiApp.addLabel(LabelType(*name));
696 manifest.addLabel(LabelType(*name));
701 defaultNameSaved = true;
702 uiApp.addLabel(LabelType(*name));
703 manifest.addLabel(LabelType(*name));
708 void TaskManifestFile::setWidgetIcons(UiApplication & uiApp)
710 DPL::OptionalString pkgname = m_context.widgetConfig.pkgname;
711 if (pkgname.IsNull()) {
712 ThrowMsg(Exceptions::InternalError, "No Package name exists.");
715 //TODO this file will need to be updated when user locale preferences
717 Assert(!!m_context.widgetHandle);
718 WidgetDAOReadOnly dao(*m_context.widgetHandle);
720 WidgetDAOReadOnly::WidgetLocalizedIconList locList = dao.getLocalizedIconList();
721 WidgetDAOReadOnly::WidgetIconList list = dao.getIconList();
722 bool defaultIconSaved = false;
726 DPL::String i = it->widgetLocale;
727 DPL::OptionalString tag = getLangTag(i); // translate en -> en_US etc
728 if (tag.IsNull()) { tag = i; }
730 generateWidgetIcon(uiApp, tag, i, it->iconId, list, defaultIconSaved);
732 DPL::OptionalString defaultLocale = dao.getDefaultlocale();
733 if (!!defaultLocale && !defaultIconSaved)
738 if (it->widgetLocale == *defaultLocale)
745 generateWidgetIcon(uiApp, DPL::OptionalString::Null,
754 void TaskManifestFile::generateWidgetIcon(UiApplication & uiApp, const DPL::OptionalString& tag, const DPL::String& language, int iconId, const WrtDB::WidgetDAOReadOnly::WidgetIconList & list, bool & defaultIconSaved)
759 locale = LocalizationUtils::BCP47LanguageTagToLocale(*tag);
763 defaultIconSaved = true;
766 DPL::OptionalString src;
769 if (icon->iconId == iconId) {
774 DPL::String iconText;
775 iconText += /*DPL::FromASCIIString(GlobalConfig::GetUserWidgetDesktopIconPath()) + L"/" +*/ getIconTargetFilename(language);
778 uiApp.addIcon(IconType(iconText,locale));
782 uiApp.addIcon(IconType(iconText));
787 void TaskManifestFile::setWidgetManifest(Manifest & manifest)
789 if(!!m_context.widgetConfig.pkgname)
791 manifest.setPackage(*m_context.widgetConfig.pkgname);
793 if(!!m_context.widgetConfig.version)
795 manifest.setVersion(*m_context.widgetConfig.version);
797 DPL::String email = (!!m_context.widgetConfig.configInfo.authorEmail ?
798 *m_context.widgetConfig.configInfo.authorEmail : L"");
799 DPL::String href = (!!m_context.widgetConfig.configInfo.authorHref ?
800 *m_context.widgetConfig.configInfo.authorHref : L"");
801 DPL::String name = (!!m_context.widgetConfig.configInfo.authorName ?
802 *m_context.widgetConfig.configInfo.authorName : L"");
803 manifest.addAuthor(Author(email,href,L"",name));
806 void TaskManifestFile::setWidgetOtherInfo(UiApplication & uiApp)
808 uiApp.setNodisplay(false);
810 //There is no "X-TIZEN-PackageType=wgt", there is not field in manifest
811 //There is no X-TIZEN-PackageID in manifest "X-TIZEN-PackageID=" << DPL::ToUTF8String(*widgetID).c_str()
812 //There is no Comment in pkgmgr "Comment=Widget application"
815 void TaskManifestFile::setAppServiceInfo(UiApplication & uiApp)
817 Assert(!!m_context.widgetHandle);
818 WidgetDAOReadOnly dao(*m_context.widgetHandle);
819 WidgetApplicationServiceList appServiceList;
820 dao.getAppServiceList(appServiceList);
822 if (appServiceList.empty()) {
823 LogInfo("Widget doesn't contain application service");
827 // x-tizen-svc=http://tizen.org/appsvc/operation/pick|NULL|image;
828 FOREACH(it, appServiceList) {
829 ApplicationService appService;
830 appService.addOperation(it->operation);
831 appService.addOperation(it->scheme);
832 appService.addOperation(it->mime);
833 uiApp.addApplicationService(appService);
837 } //namespace WidgetInstall