Package org.ofbiz.base.util

Examples of org.ofbiz.base.util.DateRange


        if (inDateRange != null) {
            dateBoundaries.add(inDateRange.start());
            dateBoundaries.add(inDateRange.end());
        }
        for (Map<String, Object>calendarEntry: calendarEntries) {
            DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
            dateBoundaries.add(calEntryRange.start());
            dateBoundaries.add(calEntryRange.end());
        }
        Date prevDateBoundary = null;
        for (Date dateBoundary: dateBoundaries) {
            if (prevDateBoundary != null) {
                DateRange dateRange = new DateRange(prevDateBoundary, dateBoundary);
                for (Map<String, Object>calendarEntry: calendarEntries) {
                    DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
                    if (calEntryRange.intersectsRange(dateRange) && !(calEntryRange.end().equals(dateRange.start()) || calEntryRange.start().equals(dateRange.end()))) {
                        List<Map<String, Object>> calendarEntryByDateRangeList = calendarEntriesByDateRange.get(dateRange);
                        if (calendarEntryByDateRangeList == null) {
                            calendarEntryByDateRangeList = FastList.newInstance();
                        }
                        calendarEntryByDateRangeList.add(calendarEntry);
View Full Code Here


            List<DateRange> periodRanges = FastList.newInstance();
            for (int i = 0; i < numPeriods; i++) {
                Timestamp curPeriodStart = UtilDateTime.adjustTimestamp(startStamp, periodType, i, timeZone, locale);
                Timestamp curPeriodEnd = UtilDateTime.adjustTimestamp(curPeriodStart, periodType, 1, timeZone, locale);
                curPeriodEnd = new Timestamp(curPeriodEnd.getTime() - 1);
                periodRanges.add(new DateRange(curPeriodStart, curPeriodEnd));
            }
            try {
                // Process recurring work efforts
                Set<GenericValue> exclusions = FastSet.newInstance();
                Set<GenericValue> inclusions = FastSet.newInstance();
                DateRange range = new DateRange(startStamp, endStamp);
                Calendar cal = UtilDateTime.toCalendar(startStamp, timeZone, locale);
                for (GenericValue workEffort : validWorkEfforts) {
                    if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
                        // check if either the workeffort is public or the requested party is a member
                        if (UtilValidate.isNotEmpty(partyIdsToUse) && !workEffort.getString("scopeEnumId").equals("WES_PUBLIC") && !partyIdsToUse.contains(workEffort.getString("partyId"))) {
                            continue;
                        }
                        TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
                        Set<Date> occurrences = tempExpr.getRange(range, cal);
                        for (Date occurrence : occurrences) {
                            for (DateRange periodRange : periodRanges) {
                                if (periodRange.includesDate(occurrence)) {
                                    GenericValue cloneWorkEffort = (GenericValue) workEffort.clone();
                                    TimeDuration duration = TimeDuration.fromNumber(workEffort.getDouble("estimatedMilliSeconds"));
                                    if (!duration.isZero()) {
                                        Calendar endCal = UtilDateTime.toCalendar(occurrence, timeZone, locale);
                                        Date endDate = duration.addToCalendar(endCal).getTime();
                                        cloneWorkEffort.set("estimatedStartDate", new Timestamp(occurrence.getTime()));
                                        cloneWorkEffort.set("estimatedCompletionDate", new Timestamp(endDate.getTime()));
                                    } else {
                                        cloneWorkEffort.set("estimatedStartDate", periodRange.startStamp());
                                        cloneWorkEffort.set("estimatedCompletionDate", periodRange.endStamp());
                                    }
                                    inclusions.add(cloneWorkEffort);
                                }
                            }
                        }
                        exclusions.add(workEffort);
                    }
                }
                validWorkEfforts.removeAll(exclusions);
                validWorkEfforts.addAll(inclusions);
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
            }

            // For each period in the set we check all work efforts to see if they fall within range
            boolean firstEntry = true;
            for (DateRange periodRange : periodRanges) {
                List<Map<String, Object>> curWorkEfforts = FastList.newInstance();
                Map<String, Object> entry = FastMap.newInstance();
                for (GenericValue workEffort : validWorkEfforts) {
                    Timestamp startDate = workEffort.getTimestamp("estimatedStartDate");
                    if (workEffort.getTimestamp("actualStartDate") != null) {
                        startDate = workEffort.getTimestamp("actualStartDate");
                    }
                    Timestamp endDate = workEffort.getTimestamp("estimatedCompletionDate");
                    if (workEffort.getTimestamp("actualCompletionDate") != null) {
                        endDate = workEffort.getTimestamp("actualCompletionDate");
                    }
                    if (endDate == null) endDate = startDate;
                    DateRange weRange = new DateRange(startDate, endDate);
                    if (periodRange.intersectsRange(weRange)) {
                        Map<String, Object> calEntry = FastMap.newInstance();
                        calEntry.put("workEffort", workEffort);
                        long length = ((weRange.end().after(endStamp) ? endStamp.getTime() : weRange.end().getTime()) - (weRange.start().before(startStamp) ? startStamp.getTime() : weRange.start().getTime()));
                        int periodSpan = (int) Math.ceil((double) length / periodLen);
                        calEntry.put("periodSpan", Integer.valueOf(periodSpan));
                        DateRange calEntryRange = new DateRange((weRange.start().before(startStamp) ? startStamp : weRange.start()), (weRange.end().after(endStamp) ? endStamp : weRange.end()));
                        calEntry.put("calEntryRange", calEntryRange);
                        if (firstEntry) {
                            // If this is the first period any valid entry is starting here
                            calEntry.put("startOfPeriod", Boolean.TRUE);
                            firstEntry = false;
View Full Code Here

        if (inDateRange != null) {
            dateBoundaries.add(inDateRange.start());
            dateBoundaries.add(inDateRange.end());
        }
        for (Map<String, Object>calendarEntry: calendarEntries) {
            DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
            dateBoundaries.add(calEntryRange.start());
            dateBoundaries.add(calEntryRange.end());
        }
        Date prevDateBoundary = null;
        for (Date dateBoundary: dateBoundaries) {
            if (prevDateBoundary != null) {
                DateRange dateRange = new DateRange(prevDateBoundary, dateBoundary);
                for (Map<String, Object>calendarEntry: calendarEntries) {
                    DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
                    if (calEntryRange.intersectsRange(dateRange) && !(calEntryRange.end().equals(dateRange.start()) || calEntryRange.start().equals(dateRange.end()))) {
                        List<Map<String, Object>> calendarEntryByDateRangeList = calendarEntriesByDateRange.get(dateRange);
                        if (calendarEntryByDateRangeList == null) {
                            calendarEntryByDateRangeList = FastList.newInstance();
                        }
                        calendarEntryByDateRangeList.add(calendarEntry);
View Full Code Here

            List<DateRange> periodRanges = FastList.newInstance();
            for (int i = 0; i < numPeriods; i++) {
                Timestamp curPeriodStart = UtilDateTime.adjustTimestamp(startStamp, periodType, i, timeZone, locale);
                Timestamp curPeriodEnd = UtilDateTime.adjustTimestamp(curPeriodStart, periodType, 1, timeZone, locale);
                curPeriodEnd = new Timestamp(curPeriodEnd.getTime() - 1);
                periodRanges.add(new DateRange(curPeriodStart, curPeriodEnd));
            }
            try {
                // Process recurring work efforts
                Set<GenericValue> exclusions = FastSet.newInstance();
                Set<GenericValue> inclusions = FastSet.newInstance();
                DateRange range = new DateRange(startStamp, endStamp);
                Calendar cal = UtilDateTime.toCalendar(startStamp, timeZone, locale);
                for (GenericValue workEffort : validWorkEfforts) {
                    if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
                        // check if either the workeffort is public or the requested party is a member
                        if (UtilValidate.isNotEmpty(partyIdsToUse) && !workEffort.getString("scopeEnumId").equals("WES_PUBLIC") && !partyIdsToUse.contains(workEffort.getString("partyId"))) {
                            continue;
                        }
                        TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
                        Set<Date> occurrences = tempExpr.getRange(range, cal);
                        for (Date occurrence : occurrences) {
                            for (DateRange periodRange : periodRanges) {
                                if (periodRange.includesDate(occurrence)) {
                                    GenericValue cloneWorkEffort = (GenericValue) workEffort.clone();
                                    TimeDuration duration = TimeDuration.fromNumber(workEffort.getDouble("estimatedMilliSeconds"));
                                    if (!duration.isZero()) {
                                        Calendar endCal = UtilDateTime.toCalendar(occurrence, timeZone, locale);
                                        Date endDate = duration.addToCalendar(endCal).getTime();
                                        cloneWorkEffort.set("estimatedStartDate", new Timestamp(occurrence.getTime()));
                                        cloneWorkEffort.set("estimatedCompletionDate", new Timestamp(endDate.getTime()));
                                    } else {
                                        cloneWorkEffort.set("estimatedStartDate", periodRange.startStamp());
                                        cloneWorkEffort.set("estimatedCompletionDate", periodRange.endStamp());
                                    }
                                    inclusions.add(cloneWorkEffort);
                                }
                            }
                        }
                        exclusions.add(workEffort);
                    }
                }
                validWorkEfforts.removeAll(exclusions);
                validWorkEfforts.addAll(inclusions);
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
            }

            // For each period in the set we check all work efforts to see if they fall within range
            boolean firstEntry = true;
            for (DateRange periodRange : periodRanges) {
                List<Map<String, Object>> curWorkEfforts = FastList.newInstance();
                Map<String, Object> entry = FastMap.newInstance();
                for (GenericValue workEffort : validWorkEfforts) {
                    Timestamp startDate = workEffort.getTimestamp("estimatedStartDate");
                    if (workEffort.getTimestamp("actualStartDate") != null) {
                        startDate = workEffort.getTimestamp("actualStartDate");
                    }
                    Timestamp endDate = workEffort.getTimestamp("estimatedCompletionDate");
                    if (workEffort.getTimestamp("actualCompletionDate") != null) {
                        endDate = workEffort.getTimestamp("actualCompletionDate");
                    }
                    if (endDate == null) endDate = startDate;
                    DateRange weRange = new DateRange(startDate, endDate);
                    if (periodRange.intersectsRange(weRange)) {
                        Map<String, Object> calEntry = FastMap.newInstance();
                        calEntry.put("workEffort", workEffort);
                        long length = ((weRange.end().after(endStamp) ? endStamp.getTime() : weRange.end().getTime()) - (weRange.start().before(startStamp) ? startStamp.getTime() : weRange.start().getTime()));
                        int periodSpan = (int) Math.ceil((double) length / periodLen);
                        calEntry.put("periodSpan", Integer.valueOf(periodSpan));
                        DateRange calEntryRange = new DateRange((weRange.start().before(startStamp) ? startStamp : weRange.start()), (weRange.end().after(endStamp) ? endStamp : weRange.end()));
                        calEntry.put("calEntryRange", calEntryRange);
                        if (firstEntry) {
                            // If this is the first period any valid entry is starting here
                            calEntry.put("startOfPeriod", Boolean.TRUE);
                            firstEntry = false;
View Full Code Here

    protected static boolean isCalendarPublished(GenericValue publishProperties) {
        if (publishProperties == null || !"PUBLISH_PROPS".equals(publishProperties.get("workEffortTypeId"))) {
            return false;
        }
        DateRange range = new DateRange(publishProperties.getTimestamp("actualStartDate"), publishProperties.getTimestamp("actualCompletionDate"));
        return range.includesDate(new Date());
    }
View Full Code Here

        if (inDateRange != null) {
            dateBoundaries.add(inDateRange.start());
            dateBoundaries.add(inDateRange.end());
        }
        for (Map<String, Object>calendarEntry: calendarEntries) {
            DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
            dateBoundaries.add(calEntryRange.start());
            dateBoundaries.add(calEntryRange.end());
        }
        Date prevDateBoundary = null;
        for (Date dateBoundary: dateBoundaries) {
            if (prevDateBoundary != null) {
                DateRange dateRange = new DateRange(prevDateBoundary, dateBoundary);
                for (Map<String, Object>calendarEntry: calendarEntries) {
                    DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
                    if (calEntryRange.intersectsRange(dateRange) && !(calEntryRange.end().equals(dateRange.start()) || calEntryRange.start().equals(dateRange.end()))) {
                        List<Map<String, Object>> calendarEntryByDateRangeList = calendarEntriesByDateRange.get(dateRange);
                        if (calendarEntryByDateRangeList == null) {
                            calendarEntryByDateRangeList = FastList.newInstance();
                        }
                        calendarEntryByDateRangeList.add(calendarEntry);
View Full Code Here

            List<DateRange> periodRanges = FastList.newInstance();
            for (int i = 0; i < numPeriods; i++) {
                Timestamp curPeriodStart = UtilDateTime.adjustTimestamp(startStamp, periodType, i, timeZone, locale);
                Timestamp curPeriodEnd = UtilDateTime.adjustTimestamp(curPeriodStart, periodType, 1, timeZone, locale);
                curPeriodEnd = new Timestamp(curPeriodEnd.getTime() - 1);
                periodRanges.add(new DateRange(curPeriodStart, curPeriodEnd));
            }
            try {
                // Process recurring work efforts
                Set<GenericValue> exclusions = FastSet.newInstance();
                Set<GenericValue> inclusions = FastSet.newInstance();
                DateRange range = new DateRange(startStamp, endStamp);
                Calendar cal = UtilDateTime.toCalendar(startStamp, timeZone, locale);
                for (GenericValue workEffort : validWorkEfforts) {
                    if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
                        // check if either the workeffort is public or the requested party is a member
                        if (UtilValidate.isNotEmpty(partyIdsToUse) && !"WES_PUBLIC".equals(workEffort.getString("scopeEnumId")) && !partyIdsToUse.contains(workEffort.getString("partyId"))) {
                            continue;
                        }
                        TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
                        Set<Date> occurrences = tempExpr.getRange(range, cal);
                        for (Date occurrence : occurrences) {
                            for (DateRange periodRange : periodRanges) {
                                if (periodRange.includesDate(occurrence)) {
                                    GenericValue cloneWorkEffort = (GenericValue) workEffort.clone();
                                    TimeDuration duration = TimeDuration.fromNumber(workEffort.getDouble("estimatedMilliSeconds"));
                                    if (!duration.isZero()) {
                                        Calendar endCal = UtilDateTime.toCalendar(occurrence, timeZone, locale);
                                        Date endDate = duration.addToCalendar(endCal).getTime();
                                        cloneWorkEffort.set("estimatedStartDate", new Timestamp(occurrence.getTime()));
                                        cloneWorkEffort.set("estimatedCompletionDate", new Timestamp(endDate.getTime()));
                                    } else {
                                        cloneWorkEffort.set("estimatedStartDate", periodRange.startStamp());
                                        cloneWorkEffort.set("estimatedCompletionDate", periodRange.endStamp());
                                    }
                                    inclusions.add(cloneWorkEffort);
                                }
                            }
                        }
                        exclusions.add(workEffort);
                    }
                }
                validWorkEfforts.removeAll(exclusions);
                validWorkEfforts.addAll(inclusions);
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
            }

            // For each period in the set we check all work efforts to see if they fall within range
            boolean firstEntry = true;
            for (DateRange periodRange : periodRanges) {
                List<Map<String, Object>> curWorkEfforts = FastList.newInstance();
                Map<String, Object> entry = FastMap.newInstance();
                for (GenericValue workEffort : validWorkEfforts) {
                    Timestamp startDate = workEffort.getTimestamp("estimatedStartDate");
                    if (workEffort.getTimestamp("actualStartDate") != null) {
                        startDate = workEffort.getTimestamp("actualStartDate");
                    }
                    Timestamp endDate = workEffort.getTimestamp("estimatedCompletionDate");
                    if (workEffort.getTimestamp("actualCompletionDate") != null) {
                        endDate = workEffort.getTimestamp("actualCompletionDate");
                    }
                    if (endDate == null) endDate = startDate;
                    DateRange weRange = new DateRange(startDate, endDate);
                    if (periodRange.intersectsRange(weRange)) {
                        Map<String, Object> calEntry = FastMap.newInstance();
                        calEntry.put("workEffort", workEffort);
                        long length = ((weRange.end().after(endStamp) ? endStamp.getTime() : weRange.end().getTime()) - (weRange.start().before(startStamp) ? startStamp.getTime() : weRange.start().getTime()));
                        int periodSpan = (int) Math.ceil((double) length / periodLen);
                        if (length % periodLen == 0 && startDate.getTime() > periodRange.start().getTime()) {
                            periodSpan++;
                        }
                        calEntry.put("periodSpan", Integer.valueOf(periodSpan));
                        DateRange calEntryRange = new DateRange((weRange.start().before(startStamp) ? startStamp : weRange.start()), (weRange.end().after(endStamp) ? endStamp : weRange.end()));
                        calEntry.put("calEntryRange", calEntryRange);
                        if (firstEntry) {
                            // If this is the first period any valid entry is starting here
                            calEntry.put("startOfPeriod", Boolean.TRUE);
                            firstEntry = false;
View Full Code Here

                paramList.add(new Cn(partyName));
            } catch (Exception e) {
                Debug.logError(e, "Error while processing related parties: ", module);
            }
        }
        DateRange range = new DateRange(workEffort.getTimestamp("estimatedStartDate"), workEffort.getTimestamp("estimatedCompletionDate"));
        eventProps.add(new DtStart(new DateTime(range.start())));
        if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
            TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
            if (tempExpr != null) {
                try {
                    ICalRecurConverter.convert(tempExpr, eventProps);
                } catch (Exception e) {
                    eventProps.add(new Description("Error while converting recurrence: " + e));
                    eventProps.add(new DtStart());
                    eventProps.add(new DtEnd());
                    return new VEvent(eventProps);
                }
            }
        } else {
            eventProps.add(new DtEnd(new DateTime(range.end())));
        }
        if (workEffort.getString("description") != null) {
            eventProps.add(new Description(workEffort.getString("description")));
        }
        return new VEvent(eventProps);
View Full Code Here

            List<DateRange> periodRanges = FastList.newInstance();
            for (int i = 0; i < numPeriods; i++) {
                Timestamp curPeriodStart = UtilDateTime.adjustTimestamp(startStamp, periodType, i, timeZone, locale);
                Timestamp curPeriodEnd = UtilDateTime.adjustTimestamp(curPeriodStart, periodType, 1, timeZone, locale);
                curPeriodEnd = new Timestamp(curPeriodEnd.getTime() - 1);
                periodRanges.add(new DateRange(curPeriodStart, curPeriodEnd));
            }
            try {
                // Process recurring work efforts
                Set<GenericValue> exclusions = FastSet.newInstance();
                Set<GenericValue> inclusions = FastSet.newInstance();
                DateRange range = new DateRange(startStamp, endStamp);
                Calendar cal = UtilDateTime.toCalendar(startStamp, timeZone, locale);
                for (GenericValue workEffort : validWorkEfforts) {
                    if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
                        TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
                        Set<Date> occurrences = tempExpr.getRange(range, cal);
                        for (Date occurrence : occurrences) {
                            for (DateRange periodRange : periodRanges) {
                                if (periodRange.includesDate(occurrence)) {
                                    GenericValue cloneWorkEffort = (GenericValue) workEffort.clone();
                                    Double durationMillis = workEffort.getDouble("estimatedMilliSeconds");
                                    if (durationMillis != null) {
                                        TimeDuration duration = TimeDuration.fromLong(durationMillis.longValue());
                                        Calendar endCal = UtilDateTime.toCalendar(occurrence, timeZone, locale);
                                        Date endDate = duration.addToCalendar(endCal).getTime();
                                        cloneWorkEffort.set("estimatedStartDate", new Timestamp(occurrence.getTime()));
                                        cloneWorkEffort.set("estimatedCompletionDate", new Timestamp(endDate.getTime()));
                                    } else {
                                        cloneWorkEffort.set("estimatedStartDate", periodRange.startStamp());
                                        cloneWorkEffort.set("estimatedCompletionDate", periodRange.endStamp());
                                    }
                                    inclusions.add(cloneWorkEffort);
                                }
                            }
                        }
                        exclusions.add(workEffort);
                    }
                }
                validWorkEfforts.removeAll(exclusions);
                validWorkEfforts.addAll(inclusions);
            } catch (GenericEntityException e) {
                Debug.logWarning(e, module);
            }

            // For each period in the set we check all work efforts to see if they fall within range
            boolean firstEntry = true;
            for (DateRange periodRange : periodRanges) {
                List<Map<String, Object>> curWorkEfforts = FastList.newInstance();
                Map<String, Object> entry = FastMap.newInstance();
                for (GenericValue workEffort : validWorkEfforts) {
                    DateRange weRange = new DateRange(workEffort.getTimestamp("estimatedStartDate"), workEffort.getTimestamp("estimatedCompletionDate"));
                    if (periodRange.intersectsRange(weRange)) {
                        Map<String, Object> calEntry = FastMap.newInstance();
                        calEntry.put("workEffort", workEffort);
                        long length = ((weRange.end().after(endStamp) ? endStamp.getTime() : weRange.end().getTime()) - (weRange.start().before(startStamp) ? startStamp.getTime() : weRange.start().getTime()));
                        int periodSpan = (int) Math.ceil((double) length / periodLen);
                        calEntry.put("periodSpan", Integer.valueOf(periodSpan));
                        if (firstEntry) {
                            // If this is the first period any valid entry is starting here
                            calEntry.put("startOfPeriod", Boolean.TRUE);
                            firstEntry = false;
                        } else {
                            boolean startOfPeriod = ((weRange.start().getTime() - periodRange.start().getTime()) >= 0);
                            calEntry.put("startOfPeriod", Boolean.valueOf(startOfPeriod));
                        }
                        curWorkEfforts.add(calEntry);
                    }
                }
View Full Code Here

        if (inDateRange != null) {
            dateBoundaries.add(inDateRange.start());
            dateBoundaries.add(inDateRange.end());
        }
        for (Map<String, Object>calendarEntry: calendarEntries) {
            DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
            dateBoundaries.add(calEntryRange.start());
            dateBoundaries.add(calEntryRange.end());
        }
        Date prevDateBoundary = null;
        for (Date dateBoundary: dateBoundaries) {
            if (prevDateBoundary != null) {
                DateRange dateRange = new DateRange(prevDateBoundary, dateBoundary);
                for (Map<String, Object>calendarEntry: calendarEntries) {
                    DateRange calEntryRange = (DateRange)calendarEntry.get("calEntryRange");
                    if (calEntryRange.intersectsRange(dateRange) && !(calEntryRange.end().equals(dateRange.start()) || calEntryRange.start().equals(dateRange.end()))) {
                        List<Map<String, Object>> calendarEntryByDateRangeList = calendarEntriesByDateRange.get(dateRange);
                        if (calendarEntryByDateRangeList == null) {
                            calendarEntryByDateRangeList = FastList.newInstance();
                        }
                        calendarEntryByDateRangeList.add(calendarEntry);
View Full Code Here

TOP

Related Classes of org.ofbiz.base.util.DateRange

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.