Package com.cloud.storage.template

Examples of com.cloud.storage.template.TemplateProp


    public Map<String, TemplateProp> getDefaultSystemVmTemplateInfo() {         
        List<VMTemplateVO> tmplts = _tmpltDao.listAllSystemVMTemplates();
        Map<String, TemplateProp> tmpltInfo = new HashMap<String, TemplateProp>();
        if (tmplts != null) {
            for (VMTemplateVO tmplt : tmplts) {
                TemplateProp routingInfo = new TemplateProp(tmplt.getUniqueName(), TemplateConstants.DEFAULT_SYSTEM_VM_TEMPLATE_PATH + tmplt.getId() + File.separator, false, false);
                tmpltInfo.put(tmplt.getUniqueName(), routingInfo);
            }
        }
        return tmpltInfo;
    }
View Full Code Here


                            _volumeStoreDao.update(volumeStore.getId(), volumeStore);
                            continue;
                        }
                        // Exists then don't download
                        if (volumeInfos.containsKey(volume.getId())) {
                            TemplateProp volInfo = volumeInfos.remove(volume.getId());
                            toBeDownloaded.remove(volumeStore);
                            s_logger.info("Volume Sync found " + volume.getUuid() + " already in the volume image store table");
                            if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
                                volumeStore.setErrorString("");
                            }
                            if (volInfo.isCorrupted()) {
                                volumeStore.setDownloadState(Status.DOWNLOAD_ERROR);
                                String msg = "Volume " + volume.getUuid() + " is corrupted on image store ";
                                volumeStore.setErrorString(msg);
                                s_logger.info("msg");
                                if (volumeStore.getDownloadUrl() == null) {
                                    msg = "Volume (" + volume.getUuid() + ") with install path " + volInfo.getInstallPath()
                                            + "is corrupted, please check in image store: " + volumeStore.getDataStoreId();
                                    s_logger.warn(msg);
                                } else {
                                    s_logger.info("Removing volume_store_ref entry for corrupted volume " + volume.getName());
                                    _volumeStoreDao.remove(volumeStore.getId());
                                    toBeDownloaded.add(volumeStore);
                                }

                            } else { // Put them in right status
                                volumeStore.setDownloadPercent(100);
                                volumeStore.setDownloadState(Status.DOWNLOADED);
                                volumeStore.setState(ObjectInDataStoreStateMachine.State.Ready);
                                volumeStore.setInstallPath(volInfo.getInstallPath());
                                volumeStore.setSize(volInfo.getSize());
                                volumeStore.setPhysicalSize(volInfo.getPhysicalSize());
                                volumeStore.setLastUpdated(new Date());
                                _volumeStoreDao.update(volumeStore.getId(), volumeStore);

                                if (volume.getSize() == 0) {
                                    // Set volume size in volumes table
                                    volume.setSize(volInfo.getSize());
                                    _volumeDao.update(volumeStore.getVolumeId(), volume);
                                }

                                if (volInfo.getSize() > 0) {
                                    try {
                                        _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()),
                                                com.cloud.configuration.Resource.ResourceType.secondary_storage, volInfo.getSize()
                                                - volInfo.getPhysicalSize());
                                    } catch (ResourceAllocationException e) {
                                        s_logger.warn(e.getMessage());
                                        _alertMgr.sendAlert(AlertManager.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
                                                volume.getDataCenterId(), volume.getPodId(), e.getMessage(), e.getMessage());
                                    } finally {
                                        _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(),
                                                com.cloud.configuration.Resource.ResourceType.secondary_storage.getOrdinal());
                                    }
                                }
                            }
                            continue;
                        }
                        // Volume is not on secondary but we should download.
                        if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
                            s_logger.info("Volume Sync did not find " + volume.getName() + " ready on image store " + storeId
                                    + ", will request download to start/resume shortly");
                            toBeDownloaded.add(volumeStore);
                        }
                    }

                    // Download volumes which haven't been downloaded yet.
                    if (toBeDownloaded.size() > 0) {
                        for (VolumeDataStoreVO volumeHost : toBeDownloaded) {
                            if (volumeHost.getDownloadUrl() == null) { // If url is null we
                                s_logger.info("Skip downloading volume " + volumeHost.getVolumeId() + " since no download url is specified.");
                                continue;
                            }
                            s_logger.debug("Volume " + volumeHost.getVolumeId() + " needs to be downloaded to " + store.getName());
                            // TODO: pass a callback later
                            VolumeInfo vol = volFactory.getVolume(volumeHost.getVolumeId());
                            createVolumeAsync(vol, store);
                        }
                    }

                    // Delete volumes which are not present on DB.
                    for (Long uniqueName : volumeInfos.keySet()) {
                        TemplateProp tInfo = volumeInfos.get(uniqueName);

                        //we cannot directly call expungeVolumeAsync here to
                        // reuse delete logic since in this case, our db does not have
                        // this template at all.
                        VolumeObjectTO tmplTO = new VolumeObjectTO();
                        tmplTO.setDataStore(store.getTO());
                        tmplTO.setPath(tInfo.getInstallPath());
                        tmplTO.setId(tInfo.getId());
                        DeleteCommand dtCommand = new DeleteCommand(tmplTO);
                        EndPoint ep = _epSelector.select(store);
                        Answer answer = ep.sendMessage(dtCommand);
                        if (answer == null || !answer.getResult()) {
                            s_logger.info("Failed to deleted volume at store: " + store.getName());

                        } else {
                            String description = "Deleted volume " + tInfo.getTemplateName() + " on secondary storage " + storeId;
                            s_logger.info(description);
                        }
                    }
                }
                finally{
View Full Code Here

            List<MockVolumeVO> volumes = _mockVolumeDao.findByStorageIdAndType(storage.getId(),
                    MockVolumeType.VOLUME);

            Map<Long, TemplateProp> templateInfos = new HashMap<Long, TemplateProp>();
            for (MockVolumeVO volume : volumes) {
                templateInfos.put(volume.getId(), new TemplateProp(volume.getName(), volume.getPath()
                        .replaceAll(storage.getMountPoint(), ""), volume.getSize(), volume.getSize(), true, false));
            }
            txn.commit();
            return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos);
        } catch (Exception ex) {
View Full Code Here

            List<MockVolumeVO> templates = _mockVolumeDao.findByStorageIdAndType(storage.getId(),
                    MockVolumeType.TEMPLATE);

            Map<String, TemplateProp> templateInfos = new HashMap<String, TemplateProp>();
            for (MockVolumeVO template : templates) {
                templateInfos.put(template.getName(), new TemplateProp(template.getName(), template.getPath()
                        .replaceAll(storage.getMountPoint(), ""), template.getSize(), template.getSize(), true, false));
            }
            return new ListTemplateAnswer(nfsUrl, templateInfos);
        } catch (Exception ex) {
            txn.rollback();
View Full Code Here

                    for (VMTemplateVO tmplt : allTemplates) {
                        String uniqueName = tmplt.getUniqueName();
                        TemplateDataStoreVO tmpltStore = _vmTemplateStoreDao.findByStoreTemplate(storeId, tmplt.getId());
                        if (templateInfos.containsKey(uniqueName)) {
                            TemplateProp tmpltInfo = templateInfos.remove(uniqueName);
                            toBeDownloaded.remove(tmplt);
                            if (tmpltStore != null) {
                                s_logger.info("Template Sync found " + uniqueName + " already in the image store");
                                if (tmpltStore.getDownloadState() != Status.DOWNLOADED) {
                                    tmpltStore.setErrorString("");
                                }
                                if (tmpltInfo.isCorrupted()) {
                                    tmpltStore.setDownloadState(Status.DOWNLOAD_ERROR);
                                    String msg = "Template " + tmplt.getName() + ":" + tmplt.getId()
                                            + " is corrupted on secondary storage " + tmpltStore.getId();
                                    tmpltStore.setErrorString(msg);
                                    s_logger.info("msg");
                                    if (tmplt.getUrl() == null) {
                                        msg = "Private Template (" + tmplt + ") with install path " + tmpltInfo.getInstallPath()
                                                + "is corrupted, please check in image store: " + tmpltStore.getDataStoreId();
                                        s_logger.warn(msg);
                                    } else {
                                        s_logger.info("Removing template_store_ref entry for corrupted template " + tmplt.getName());
                                        _vmTemplateStoreDao.remove(tmpltStore.getId());
                                        toBeDownloaded.add(tmplt);
                                    }

                                } else {
                                    tmpltStore.setDownloadPercent(100);
                                    tmpltStore.setDownloadState(Status.DOWNLOADED);
                                    tmpltStore.setState(ObjectInDataStoreStateMachine.State.Ready);
                                    tmpltStore.setInstallPath(tmpltInfo.getInstallPath());
                                    tmpltStore.setSize(tmpltInfo.getSize());
                                    tmpltStore.setPhysicalSize(tmpltInfo.getPhysicalSize());
                                    tmpltStore.setLastUpdated(new Date());
                                    // update size in vm_template table
                                    VMTemplateVO tmlpt = _templateDao.findById(tmplt.getId());
                                    tmlpt.setSize(tmpltInfo.getSize());
                                    _templateDao.update(tmplt.getId(), tmlpt);

                                    // Skipping limit checks for SYSTEM Account and for the templates created from volumes or snapshots
                                    // which already got checked and incremented during createTemplate API call.
                                    if (tmpltInfo.getSize() > 0 && tmplt.getAccountId() != Account.ACCOUNT_ID_SYSTEM && tmplt.getUrl() != null) {
                                        long accountId = tmplt.getAccountId();
                                        try {
                                            _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(accountId),
                                                    com.cloud.configuration.Resource.ResourceType.secondary_storage,
                                                    tmpltInfo.getSize() - UriUtils.getRemoteSize(tmplt.getUrl()));
                                        } catch (ResourceAllocationException e) {
                                            s_logger.warn(e.getMessage());
                                            _alertMgr.sendAlert(AlertManager.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED, zoneId, null,
                                                    e.getMessage(), e.getMessage());
                                        } finally {
                                            _resourceLimitMgr.recalculateResourceCount(accountId, _accountMgr.getAccount(accountId)
                                                    .getDomainId(), com.cloud.configuration.Resource.ResourceType.secondary_storage
                                                    .getOrdinal());
                                        }
                                    }
                                }
                                _vmTemplateStoreDao.update(tmpltStore.getId(), tmpltStore);
                            } else {
                                tmpltStore = new TemplateDataStoreVO(storeId, tmplt.getId(), new Date(), 100, Status.DOWNLOADED,
                                        null, null, null, tmpltInfo.getInstallPath(), tmplt.getUrl());
                                tmpltStore.setSize(tmpltInfo.getSize());
                                tmpltStore.setPhysicalSize(tmpltInfo.getPhysicalSize());
                                tmpltStore.setDataStoreRole(store.getRole());
                                _vmTemplateStoreDao.persist(tmpltStore);

                                // update size in vm_template table
                                VMTemplateVO tmlpt = _templateDao.findById(tmplt.getId());
                                tmlpt.setSize(tmpltInfo.getSize());
                                _templateDao.update(tmplt.getId(), tmlpt);
                                associateTemplateToZone(tmplt.getId(), zoneId);


                            }
                        } else {
                            s_logger.info("Template Sync did not find " + uniqueName + " on image store " + storeId + ", may request download based on available hypervisor types");
                            if (tmpltStore != null) {
                                s_logger.info("Removing leftover template " + uniqueName + " entry from template store table");
                                // remove those leftover entries
                                _vmTemplateStoreDao.remove(tmpltStore.getId());
                            }
                        }
                    }

                    if (toBeDownloaded.size() > 0) {
                        /* Only download templates whose hypervirsor type is in the zone */
                        List<HypervisorType> availHypers = _clusterDao.getAvailableHypervisorInZone(zoneId);
                        if (availHypers.isEmpty()) {
                            /*
                             * This is for cloudzone, local secondary storage resource
                             * started before cluster created
                             */
                            availHypers.add(HypervisorType.KVM);
                        }
                        /* Baremetal need not to download any template */
                        availHypers.remove(HypervisorType.BareMetal);
                        availHypers.add(HypervisorType.None); // bug 9809: resume ISO
                        // download.
                        for (VMTemplateVO tmplt : toBeDownloaded) {
                            if (tmplt.getUrl() == null) { // If url is null we can't
                                s_logger.info("Skip downloading template " + tmplt.getUniqueName() + " since no url is specified.");
                                continue;
                            }
                            // if this is private template, skip sync to a new image store
                            if (!tmplt.isPublicTemplate() && !tmplt.isFeatured() && tmplt.getTemplateType() != TemplateType.SYSTEM) {
                                s_logger.info("Skip sync downloading private template " + tmplt.getUniqueName() + " to a new image store");
                                continue;
                            }

                            if (availHypers.contains(tmplt.getHypervisorType())) {
                                s_logger.info("Downloading template " + tmplt.getUniqueName() + " to image store "
                                        + store.getName());
                                associateTemplateToZone(tmplt.getId(), zoneId);
                                TemplateInfo tmpl = _templateFactory.getTemplate(tmplt.getId(), DataStoreRole.Image);
                                createTemplateAsync(tmpl, store, null);
                            } else {
                                s_logger.info("Skip downloading template " + tmplt.getUniqueName() + " since current data center does not have hypervisor "
                                        + tmplt.getHypervisorType().toString());
                            }
                        }
                    }

                    for (String uniqueName : templateInfos.keySet()) {
                        TemplateProp tInfo = templateInfos.get(uniqueName);
                        if (_tmpltMgr.templateIsDeleteable(tInfo.getId())) {
                            // we cannot directly call deleteTemplateSync here to
                            // reuse delete logic since in this case, our db does not have
                            // this template at all.
                            TemplateObjectTO tmplTO = new TemplateObjectTO();
                            tmplTO.setDataStore(store.getTO());
                            tmplTO.setPath(tInfo.getInstallPath());
                            tmplTO.setId(tInfo.getId());
                            DeleteCommand dtCommand = new DeleteCommand(tmplTO);
                            EndPoint ep = _epSelector.select(store);
                            Answer answer = ep.sendMessage(dtCommand);
                            if (answer == null || !answer.getResult()) {
                                s_logger.info("Failed to deleted template at store: " + store.getName());

                            } else {
                                String description = "Deleted template " + tInfo.getTemplateName() + " on secondary storage "
                                        + storeId;
                                s_logger.info(description);
                            }

                        }
View Full Code Here

            } catch (IOException e) {
                s_logger.warn("Unable to load template location " + path, e);
                continue;
            }

            TemplateProp tInfo = loc.getTemplateInfo();

      if ((tInfo.getSize() == tInfo.getPhysicalSize())
          && (tInfo.getInstallPath().endsWith(ImageFormat.OVA.getFileExtension()))) {
                try {
                    Processor processor = _processors.get("VMDK Processor");
                    VmdkProcessor vmdkProcessor = (VmdkProcessor) processor;
                    long vSize =
                            vmdkProcessor.getTemplateVirtualSize(
                                    path,
                                    tInfo.getInstallPath().substring(
                                            tInfo.getInstallPath().lastIndexOf(File.separator) + 1));
                    tInfo.setSize(vSize);
                    loc.updateVirtualSize(vSize);
                    loc.save();
                } catch (Exception e) {
          s_logger.error("Unable to get the virtual size of the template: " + tInfo.getInstallPath()
              + " due to " + e.getMessage());
                }
            }

      result.put(tInfo.getTemplateName(), tInfo);
      s_logger.debug("Added template name: " + tInfo.getTemplateName() + ", path: " + tmplt);
        }
        /*
        for (String tmplt : isoTmplts) {
            String tmp[];
            tmp = tmplt.split("/");
View Full Code Here

            } catch (IOException e) {
                s_logger.warn("Unable to load volume location " + path, e);
                continue;
            }

            TemplateProp vInfo = loc.getTemplateInfo();

      if ((vInfo.getSize() == vInfo.getPhysicalSize())
          && (vInfo.getInstallPath().endsWith(ImageFormat.OVA.getFileExtension()))) {
                try {
                    Processor processor = _processors.get("VMDK Processor");
                    VmdkProcessor vmdkProcessor = (VmdkProcessor)processor;
          long vSize =
              vmdkProcessor.getTemplateVirtualSize(
                  path,
                  vInfo.getInstallPath().substring(
                      vInfo.getInstallPath().lastIndexOf(File.separator) + 1));
          vInfo.setSize(vSize);
                    loc.updateVirtualSize(vSize);
                    loc.save();
                } catch (Exception e) {
          s_logger.error("Unable to get the virtual size of the volume: " + vInfo.getInstallPath()
              + " due to " + e.getMessage());
                }
            }

            result.put(vInfo.getId(), vInfo);
      s_logger.debug("Added volume name: " + vInfo.getTemplateName() + ", path: " + vol);
        }
        return result;
    }
View Full Code Here

                            _volumeStoreDao.update(volumeStore.getId(), volumeStore);
                            continue;
                        }
                        // Exists then don't download
                        if (volumeInfos.containsKey(volume.getId())) {
                            TemplateProp volInfo = volumeInfos.remove(volume.getId());
                            toBeDownloaded.remove(volumeStore);
                            s_logger.info("Volume Sync found " + volume.getUuid() + " already in the volume image store table");
                            if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
                                volumeStore.setErrorString("");
                            }
                            if (volInfo.isCorrupted()) {
                                volumeStore.setDownloadState(Status.DOWNLOAD_ERROR);
                                String msg = "Volume " + volume.getUuid() + " is corrupted on image store ";
                                volumeStore.setErrorString(msg);
                                s_logger.info("msg");
                                if (volumeStore.getDownloadUrl() == null) {
                                    msg = "Volume (" + volume.getUuid() + ") with install path " + volInfo.getInstallPath()
                                            + "is corrupted, please check in image store: " + volumeStore.getDataStoreId();
                                    s_logger.warn(msg);
                                } else {
                                    s_logger.info("Removing volume_store_ref entry for corrupted volume " + volume.getName());
                                    _volumeStoreDao.remove(volumeStore.getId());
                                    toBeDownloaded.add(volumeStore);
                                }

                            } else { // Put them in right status
                                volumeStore.setDownloadPercent(100);
                                volumeStore.setDownloadState(Status.DOWNLOADED);
                                volumeStore.setState(ObjectInDataStoreStateMachine.State.Ready);
                                volumeStore.setInstallPath(volInfo.getInstallPath());
                                volumeStore.setSize(volInfo.getSize());
                                volumeStore.setPhysicalSize(volInfo.getPhysicalSize());
                                volumeStore.setLastUpdated(new Date());
                                _volumeStoreDao.update(volumeStore.getId(), volumeStore);

                                if (volume.getSize() == 0) {
                                    // Set volume size in volumes table
                                    volume.setSize(volInfo.getSize());
                                    _volumeDao.update(volumeStore.getVolumeId(), volume);
                                }

                                if (volInfo.getSize() > 0) {
                                    try {
                                        _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(volume.getAccountId()),
                                                com.cloud.configuration.Resource.ResourceType.secondary_storage, volInfo.getSize()
                                                - volInfo.getPhysicalSize());
                                    } catch (ResourceAllocationException e) {
                                        s_logger.warn(e.getMessage());
                                        _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED,
                                                volume.getDataCenterId(), volume.getPodId(), e.getMessage(), e.getMessage());
                                    } finally {
                                        _resourceLimitMgr.recalculateResourceCount(volume.getAccountId(), volume.getDomainId(),
                                                com.cloud.configuration.Resource.ResourceType.secondary_storage.getOrdinal());
                                    }
                                }
                            }
                            continue;
                        }
                        // Volume is not on secondary but we should download.
                        if (volumeStore.getDownloadState() != Status.DOWNLOADED) {
                            s_logger.info("Volume Sync did not find " + volume.getName() + " ready on image store " + storeId
                                    + ", will request download to start/resume shortly");
                            toBeDownloaded.add(volumeStore);
                        }
                    }

                    // Download volumes which haven't been downloaded yet.
                    if (toBeDownloaded.size() > 0) {
                        for (VolumeDataStoreVO volumeHost : toBeDownloaded) {
                            if (volumeHost.getDownloadUrl() == null) { // If url is null we
                                s_logger.info("Skip downloading volume " + volumeHost.getVolumeId() + " since no download url is specified.");
                                continue;
                            }

                            // if this is a region store, and there is already an DOWNLOADED entry there without install_path information, which
                            // means that this is a duplicate entry from migration of previous NFS to staging.
                            if (store.getScope().getScopeType() == ScopeType.REGION) {
                                if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED
                                        && volumeHost.getInstallPath() == null) {
                                    s_logger.info("Skip sync volume for migration of previous NFS to object store");
                                    continue;
                                }
                            }

                            s_logger.debug("Volume " + volumeHost.getVolumeId() + " needs to be downloaded to " + store.getName());
                            // TODO: pass a callback later
                            VolumeInfo vol = volFactory.getVolume(volumeHost.getVolumeId());
                            createVolumeAsync(vol, store);
                        }
                    }

                    // Delete volumes which are not present on DB.
                    for (Long uniqueName : volumeInfos.keySet()) {
                        TemplateProp tInfo = volumeInfos.get(uniqueName);

                        //we cannot directly call expungeVolumeAsync here to
                        // reuse delete logic since in this case, our db does not have
                        // this template at all.
                        VolumeObjectTO tmplTO = new VolumeObjectTO();
                        tmplTO.setDataStore(store.getTO());
                        tmplTO.setPath(tInfo.getInstallPath());
                        tmplTO.setId(tInfo.getId());
                        DeleteCommand dtCommand = new DeleteCommand(tmplTO);
                        EndPoint ep = _epSelector.select(store);
                        Answer answer = null;
                        if (ep == null) {
                            String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
                            s_logger.error(errMsg);
                            answer = new Answer(dtCommand, false, errMsg);
                        } else {
                            answer = ep.sendMessage(dtCommand);
                        }
                        if (answer == null || !answer.getResult()) {
                            s_logger.info("Failed to deleted volume at store: " + store.getName());

                        } else {
                            String description = "Deleted volume " + tInfo.getTemplateName() + " on secondary storage " + storeId;
                            s_logger.info(description);
                        }
                    }
                }
                finally{
View Full Code Here

            TemplateLocation loc = new TemplateLocation(_storage, destPath);
            loc.create(1, true, templateUuid);
            loc.addFormat(info);
            loc.save();
            TemplateProp prop = loc.getTemplateInfo();
            TemplateObjectTO newTemplate = new TemplateObjectTO();
            newTemplate.setPath(destData.getPath() + File.separator + templateName);
            newTemplate.setFormat(ImageFormat.VHD);
            newTemplate.setSize(prop.getSize());
            newTemplate.setPhysicalSize(prop.getPhysicalSize());
            newTemplate.setName(templateUuid);
            return new CopyCmdAnswer(newTemplate);
        } catch (ConfigurationException e) {
            s_logger.debug("Failed to create template from snapshot: " + e.toString());
            errMsg = e.toString();
View Full Code Here

                TemplateLocation loc = new TemplateLocation(_storage, destPath);
                loc.create(1, true, destData.getName());
                loc.addFormat(info);
                loc.save();

                TemplateProp prop = loc.getTemplateInfo();
                TemplateObjectTO newTemplate = new TemplateObjectTO();
                newTemplate.setPath(destData.getPath() + File.separator + fileName);
                newTemplate.setFormat(srcFormat);
                newTemplate.setSize(prop.getSize());
                newTemplate.setPhysicalSize(prop.getPhysicalSize());
                return new CopyCmdAnswer(newTemplate);
            } catch (ConfigurationException e) {
                s_logger.debug("Failed to create template:" + e.toString());
                return new CopyCmdAnswer(e.toString());
            } catch (IOException e) {
View Full Code Here

TOP

Related Classes of com.cloud.storage.template.TemplateProp

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.