Package org.traccar.model

Examples of org.traccar.model.ExtendedInfoFormatter


            return null;
        }

        // Create new position
        Position position = new Position();
        ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
        Integer index = 1;

        // Identification
        String imei = parser.group(index++);
        try {
            position.setDeviceId(getDataManager().getDeviceByImei(imei).getId());
        } catch(Exception error) {
            Log.warning("Unknown device - " + imei);
            return null;
        }

        // Time
        Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        time.clear();
        time.set(Calendar.HOUR_OF_DAY, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MILLISECOND, Integer.valueOf(parser.group(index++)));

        // Validity
        position.setValid(parser.group(index++).compareTo("A") == 0);

        // Latitude
        Double latitude = Double.valueOf(parser.group(index++));
        latitude += Double.valueOf(parser.group(index++)) / 60;
        if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
        position.setLatitude(latitude);

        // Longitude
        Double longitude = Double.valueOf(parser.group(index++));
        longitude += Double.valueOf(parser.group(index++)) / 60;
        if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
        position.setLongitude(longitude);

        // Altitude
        position.setAltitude(0.0);

        // Speed
        position.setSpeed(Double.valueOf(parser.group(index++)));

        // Course
        String course = parser.group(index++);
        if (course != null) {
            position.setCourse(Double.valueOf(course));
        } else {
            position.setCourse(0.0);
        }

        // Date
        time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
        time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
        position.setTime(time.getTime());

        position.setExtendedInfo(extendedInfo.toString());
        return position;
    }
View Full Code Here


                recordCount = buf.readUnsignedShort();
            }

            for (int j = 0; j < recordCount; j++) {
                Position position = new Position();
                ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
                position.setDeviceId(deviceId);

                // Message index
                int subtype = type;
                if (type == MSG_TYPE_LOG_RECORDS) {
                    extendedInfo.set("archive", true);
                    lastIndex = buf.readUnsignedInt() + 1;
                    extendedInfo.set("index", lastIndex);

                    subtype = buf.readUnsignedShort();
                    if (subtype != MSG_TYPE_CURRENT_GPS_DATA && subtype != MSG_TYPE_STATE_FULL_INFO_T104) {
                        buf.skipBytes(buf.readUnsignedShort());
                        continue;
                    }
                    buf.readUnsignedShort(); // length
                }

                // Time
                Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                time.clear();
                time.setTimeInMillis(buf.readUnsignedInt() * 1000);
                position.setTime(time.getTime());

                // Latitude
                position.setLatitude(buf.readInt() * 180.0 / 0x7FFFFFFF);

                // Longitude
                position.setLongitude(buf.readInt() * 180.0 / 0x7FFFFFFF);

                // Speed and Validity
                if (subtype == MSG_TYPE_STATE_FULL_INFO_T104) {
                    int speed = buf.readUnsignedByte();
                    position.setValid(speed != 255);
                    position.setSpeed(speed * 0.539957);
                    extendedInfo.set("hdop", buf.readByte());
                } else {
                    int speed = buf.readShort();
                    position.setValid(speed != -1);
                    position.setSpeed(speed / 100.0 * 0.539957);
                }

                // Course
                position.setCourse(buf.readShort() / 100.0);

                // Altitude
                position.setAltitude((double) buf.readShort());

                if (subtype == MSG_TYPE_STATE_FULL_INFO_T104) {

                    // Satellites
                    extendedInfo.set("satellites", buf.readUnsignedByte());
                   
                    // Cell signal
                    extendedInfo.set("gsm", buf.readUnsignedByte());

                    // Event type
                    extendedInfo.set("event", buf.readUnsignedShort());

                    // Milage
                    extendedInfo.set("milage", buf.readUnsignedInt());

                    // Input/Output
                    extendedInfo.set("input", buf.readUnsignedByte());
                    extendedInfo.set("output", buf.readUnsignedByte());
                   
                    // Analog sensors
                    for (int i = 1; i <= 8; i++) {
                        extendedInfo.set("adc" + i, buf.readUnsignedShort());
                    }
                   
                    // Counters
                    extendedInfo.set("c0", buf.readUnsignedInt());
                    extendedInfo.set("c1", buf.readUnsignedInt());
                    extendedInfo.set("c2", buf.readUnsignedInt());
                }

                // Extended info
                position.setExtendedInfo(extendedInfo.toString());

                positions.add(position);
            }

            // Skip CRC
View Full Code Here

            return null;
        }
       
        // Create new position
        Position position = new Position();
        ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
        Integer index = 1;
        String type = parser.group(index++);

        // Device
        String id = parser.group(index++);
        try {
            position.setDeviceId(getDataManager().getDeviceByImei(id).getId());
        } catch(Exception error) {
            Log.warning("Unknown device - " + id);
            return null;
        }
       
        // Time
        Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        time.clear();
        time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
        time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.HOUR_OF_DAY, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));
        position.setTime(time.getTime());

        // Longitude
        String hemisphere = parser.group(index++);
        Double longitude = Double.valueOf(parser.group(index++));
        if (hemisphere.compareTo("W") == 0) longitude = -longitude;
        position.setLongitude(longitude);

        // Latitude
        hemisphere = parser.group(index++);
        Double latitude = Double.valueOf(parser.group(index++));
        if (hemisphere.compareTo("S") == 0) latitude = -latitude;
        position.setLatitude(latitude);
       
        // Altitude
        String altitude = parser.group(index++);
        if (altitude != null) {
            position.setAltitude(Double.valueOf(altitude));
        } else {
            position.setAltitude(0.0);
        }

        // Speed
        position.setSpeed(Double.valueOf(parser.group(index++)));

        // Course
        position.setCourse(Double.valueOf(parser.group(index++)));
       
        // Satellites
        int satellites = Integer.valueOf(parser.group(index++));
        position.setValid(satellites >= 3);
        extendedInfo.set("satellites", satellites);
       
        // Report identifier
        String reportId = parser.group(index++);
       
        // Status
        extendedInfo.set("status", parser.group(index++));

        // Send response
        if (type.equals("KP") || type.equals("EP") || type.equals("EP")) {
            if (channel != null) {
                channel.write("%AT+" + type + "=" + reportId + "\r\n");
            }
        }
       
        position.setExtendedInfo(extendedInfo.toString());
        return position;
    }
View Full Code Here

            return null;
        }

        // Create new position
        Position position = new Position();
        ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());

        Integer index = 1;

        // Serial
        extendedInfo.set("serial", parser.group(index++));

        // Number
        extendedInfo.set("number", parser.group(index++));

        // Time
        Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        time.clear();
        time.set(Calendar.HOUR_OF_DAY, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MILLISECOND, Integer.valueOf(parser.group(index++)));

        // Validity
        position.setValid(parser.group(index++).compareTo("A") == 0 ? true : false);

        // Latitude
        Double latitude = Double.valueOf(parser.group(index++));
        latitude += Double.valueOf(parser.group(index++)) / 60;
        if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
        position.setLatitude(latitude);

        // Longitude
        Double longitude = Double.valueOf(parser.group(index++));
        longitude += Double.valueOf(parser.group(index++)) / 60;
        if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
        position.setLongitude(longitude);

        // Speed
        position.setSpeed(Double.valueOf(parser.group(index++)));

        // Course
        String course = parser.group(index++);
        if (course != null) {
            position.setCourse(Double.valueOf(course));
        } else {
            position.setCourse(0.0);
        }

        // Date
        time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
        time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
        position.setTime(time.getTime());

        // Signal
        extendedInfo.set("signal", parser.group(index++));

        // Alarm
        extendedInfo.set("alarm", parser.group(index++));

        // Get device by IMEI
        String imei = parser.group(index++);
        try {
            position.setDeviceId(getDataManager().getDeviceByImei(imei).getId());
        } catch(Exception error) {
            Log.warning("Unknown device - " + imei);
            return null;
        }

        // Satellites
        extendedInfo.set("satellites", parser.group(index++).replaceFirst ("^0*(?![\\.$])", ""));

        // Altitude
        String altitude = parser.group(index++);
        if (altitude != null) {
            position.setAltitude(Double.valueOf(altitude));
        } else {
            position.setAltitude(0.0);
        }

        // Power
        extendedInfo.set("power", Double.valueOf(parser.group(index++)));

        // Extended info
        position.setExtendedInfo(extendedInfo.toString());

        return position;
    }
View Full Code Here

        while (buf.readable()) {

            // Create new position
            Position position = new Position();
            position.setDeviceId(deviceId);
            ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());

            // Date and time
            position.setTime(new Date(buf.readUnsignedInt() * 1000)); // gps time
            buf.readUnsignedInt(); // rtc time
            buf.readUnsignedInt(); // send time

            // Coordinates
            position.setValid(true);
            position.setLongitude(buf.readInt() * 0.000001);
            position.setLatitude(buf.readInt() * 0.000001);
            position.setAltitude(0.0);

            // Course
            position.setCourse((double) buf.readUnsignedShort());

            // Report type
            extendedInfo.set("type", buf.readUnsignedByte());

            // Milage
            extendedInfo.set("milage", buf.readUnsignedInt() * 0.1);

            // Accuracy
            extendedInfo.set("hdop", buf.readUnsignedShort() * 0.1);

            // Input
            extendedInfo.set("input", buf.readUnsignedByte());

            // Speed
            position.setSpeed(buf.readUnsignedShort() * 0.539957);

            // Output
            extendedInfo.set("output", buf.readUnsignedByte());

            // ADC
            extendedInfo.set("adc", buf.readUnsignedShort() * 0.001);

            // Driver
            extendedInfo.set("driver", readString(buf));

            // Temperature
            extendedInfo.set("temperature1", buf.readShort() * 0.1);
            extendedInfo.set("temperature2", buf.readShort() * 0.1);

            // Text Message
            extendedInfo.set("message", readString(buf));

            // With AT$FORM Command you can extend atrack protocol.
            // For example adding AT$FORM %FC /Fuel used you can add the line in this position:
            // extendedInfo.set("fuelused", buf.readUnsignedInt() * 0.1);

            position.setExtendedInfo(extendedInfo.toString());
            positions.add(position);
        }

        return positions;
    }
View Full Code Here

                recordCount = buf.readUnsignedShort();
            }

            for (int j = 0; j < recordCount; j++) {
                Position position = new Position();
                ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
                position.setDeviceId(deviceId);

                // Message index
                if (type == MSG_LOGMSG) {
                    extendedInfo.set("archive", true);
                    int subtype = buf.readUnsignedShort();
                    if (subtype == MSG_ALARM) {
                        extendedInfo.set("alarm", true);
                    }
                    if (buf.readUnsignedShort() > buf.readableBytes()) {
                        lastIndex += 1;
                        break; // workaround for device bug
                    }
                    lastIndex = buf.readUnsignedInt();
                    extendedInfo.set("index", lastIndex);
                } else {
                    newIndex = buf.readUnsignedInt();
                }

                // Time
                Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                time.clear();
                time.setTimeInMillis(buf.readUnsignedInt() * 1000);
                position.setTime(time.getTime());

                // Latitude
                position.setLatitude(((double) buf.readInt()) / 0x7FFFFFFF * 180.0);

                // Longitude
                position.setLongitude(((double) buf.readInt()) / 0x7FFFFFFF * 180.0);

                // Speed
                position.setSpeed(((double) buf.readUnsignedInt()) / 100);

                // Course
                position.setCourse(((double) buf.readUnsignedShort()) / 100);

                // Altitude
                position.setAltitude(((double) buf.readUnsignedShort()) / 100);

                // Satellites
                int satellitesNumber = buf.readUnsignedByte();
                extendedInfo.set("satellites", satellitesNumber);

                // Validity
                position.setValid(satellitesNumber >= 3); // TODO: probably wrong

                // Cell signal
                extendedInfo.set("gsm", buf.readUnsignedByte());

                // Milage
                extendedInfo.set("milage", buf.readUnsignedInt());

                long extraFlags = buf.readLong();

                // Analog inputs
                if ((extraFlags & 0x1) == 0x1) {
                    int count = buf.readUnsignedShort();
                    for (int i = 1; i <= count; i++) {
                        extendedInfo.set("adc" + i, buf.readUnsignedShort());
                    }

                }

                // CAN adapter
                if ((extraFlags & 0x2) == 0x2) {
                    int size = buf.readUnsignedShort();
                    extendedInfo.set("can", buf.toString(buf.readerIndex(), size, Charset.defaultCharset()));
                    buf.skipBytes(size);
                }

                // Passenger sensor
                if ((extraFlags & 0x4) == 0x4) {
                    int size = buf.readUnsignedShort();

                    // Convert binary data to hex
                    StringBuilder hex = new StringBuilder();
                    for (int i = buf.readerIndex(); i < buf.readerIndex() + size; i++) {
                        byte b = buf.getByte(i);
                        hex.append(HEX_CHARS.charAt((b & 0xf0) >> 4));
                        hex.append(HEX_CHARS.charAt((b & 0x0F)));
                    }

                    extendedInfo.set("passenger", hex);

                    buf.skipBytes(size);
                }

                // Send response for alarm message
                if (type == MSG_ALARM) {
                    byte[] response = {(byte)0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
                    channel.write(ChannelBuffers.wrappedBuffer(response));

                    extendedInfo.set("alarm", true);
                }

                // Skip CRC
                buf.readUnsignedInt();

                // Extended info
                position.setExtendedInfo(extendedInfo.toString());

                positions.add(position);
            }

            requestArchive(channel);
View Full Code Here

            return null;
        }

        // Create new position
        Position position = new Position();
        ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());

        Integer index = 1;

        // Identification
        String imei = parser.group(index++);
        try {
            position.setDeviceId(getDataManager().getDeviceByImei(imei).getId());
        } catch(Exception error) {
            Log.warning("Unknown device - " + imei);
            return null;
        }

        // Event
        extendedInfo.set("event", parser.group(index++));

        // Coordinates
        position.setLatitude(Double.valueOf(parser.group(index++)));
        position.setLongitude(Double.valueOf(parser.group(index++)));

        // Time
        Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
        time.clear();
        time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
        time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.HOUR_OF_DAY, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
        time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));
        position.setTime(time.getTime());

        // Validity
        position.setValid(parser.group(index++).compareTo("A") == 0);

        // Satellites
        extendedInfo.set("satellites", parser.group(index++));

        // GSM Signal
        extendedInfo.set("gsm", parser.group(index++));

        // Speed
        position.setSpeed(Double.valueOf(parser.group(index++)) * 0.539957);

        // Course
        position.setCourse(Double.valueOf(parser.group(index++)));

        // HDOP
        extendedInfo.set("hdop", parser.group(index++));

        // Altitude
        position.setAltitude(Double.valueOf(parser.group(index++)));

        // Other
        extendedInfo.set("milage", parser.group(index++));
        extendedInfo.set("runtime", parser.group(index++));
        extendedInfo.set("cell", parser.group(index++));
        extendedInfo.set("state", parser.group(index++));
       
        // ADC
        String adc1 = parser.group(index++);
        if (adc1 != null) {
            extendedInfo.set("adc1", Integer.parseInt(adc1, 16));
        }
        String adc2 = parser.group(index++);
        if (adc2 != null) {
            extendedInfo.set("adc2", Integer.parseInt(adc2, 16));
        }
        String adc3 = parser.group(index++);
        if (adc3 != null) {
            extendedInfo.set("adc3", Integer.parseInt(adc3, 16));
        }
        extendedInfo.set("battery", Integer.parseInt(parser.group(index++), 16));
        extendedInfo.set("power", Integer.parseInt(parser.group(index++), 16));
       
        // Extended info
        position.setExtendedInfo(extendedInfo.toString());

        return position;
    }
View Full Code Here

        buf.skipBytes(index + 1 + 15 + 1 + 3 + 1 + 2 + 2 + 4);
       
        while (buf.readableBytes() >= 0x34) {
           
            Position position = new Position();
            ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
            position.setDeviceId(deviceId);
           
            // Event
            extendedInfo.set("event", buf.readUnsignedByte());
           
            // Location
            position.setLatitude(buf.readInt() * 0.000001);
            position.setLongitude(buf.readInt() * 0.000001);
           
            // Time (946684800 - timestamp for 2000-01-01)
            position.setTime(new Date((946684800 + buf.readUnsignedInt()) * 1000));

            // Validity
            position.setValid(buf.readUnsignedByte() == 1);

            // Satellites
            extendedInfo.set("satellites", buf.readUnsignedByte());
           
            // GSM Signal
            extendedInfo.set("gsm", buf.readUnsignedByte());

            // Speed
            position.setSpeed(buf.readUnsignedShort() * 0.539957);

            // Course
            position.setCourse((double) buf.readUnsignedShort());

            // HDOP
            extendedInfo.set("hdop", buf.readUnsignedShort() * 0.1);

            // Altitude
            position.setAltitude((double) buf.readUnsignedShort());

            // Other
            extendedInfo.set("milage", buf.readUnsignedInt());
            extendedInfo.set("runtime", buf.readUnsignedInt());
            extendedInfo.set("cell",
                    buf.readUnsignedShort() + "|" + buf.readUnsignedShort() + "|" +
                    buf.readUnsignedShort() + "|" + buf.readUnsignedShort());
            extendedInfo.set("state", buf.readUnsignedShort());
       
            // ADC
            extendedInfo.set("adc1", buf.readUnsignedShort());
            extendedInfo.set("battery", buf.readUnsignedShort() * 0.01);
            extendedInfo.set("power", buf.readUnsignedShort());
           
            buf.readUnsignedInt(); // geo-fence
           
            position.setExtendedInfo(extendedInfo.toString());
            positions.add(position);
        }
       
        // Delete recorded data
        if (channel != null) {
View Full Code Here

                return null;
            }

            // Create new position
            Position position = new Position();
            ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
            position.setDeviceId(deviceId);

            Integer index = 1;

            // Time
            Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
            time.clear();
            time.set(Calendar.HOUR_OF_DAY, Integer.valueOf(parser.group(index++)));
            time.set(Calendar.MINUTE, Integer.valueOf(parser.group(index++)));
            time.set(Calendar.SECOND, Integer.valueOf(parser.group(index++)));

            // Validity
            position.setValid(parser.group(index++).compareTo("A") == 0 ? true : false);

            // Latitude
            Double latitude = Double.valueOf(parser.group(index++));
            latitude += Double.valueOf(parser.group(index++)) / 60;
            if (parser.group(index++).compareTo("S") == 0) latitude = -latitude;
            position.setLatitude(latitude);

            // Longitude
            Double longitude = Double.valueOf(parser.group(index++));
            longitude += Double.valueOf(parser.group(index++)) / 60;
            if (parser.group(index++).compareTo("W") == 0) longitude = -longitude;
            position.setLongitude(longitude);

            // Speed
            position.setSpeed(Double.valueOf(parser.group(index++)));

            // Course
            position.setCourse(0.0);

            // Date
            time.set(Calendar.DAY_OF_MONTH, Integer.valueOf(parser.group(index++)));
            time.set(Calendar.MONTH, Integer.valueOf(parser.group(index++)) - 1);
            time.set(Calendar.YEAR, 2000 + Integer.valueOf(parser.group(index++)));
            position.setTime(time.getTime());

            // Altitude
            position.setAltitude(0.0);

            position.setExtendedInfo(extendedInfo.toString());
            return position;
        }

        return null;
    }
View Full Code Here

            for (int i = 0; i < (header & 0x0f); i++) {
               
                // Create new position
                Position position = new Position();
                position.setDeviceId(deviceId);
                ExtendedInfoFormatter extendedInfo = new ExtendedInfoFormatter(getProtocol());
               
                extendedInfo.set("event", buf.readUnsignedByte());
                buf.readUnsignedByte(); // length
                extendedInfo.set("flag1", buf.readUnsignedByte());
                extendedInfo.set("flag2", buf.readUnsignedByte());
               
                // Location
                position.setLatitude(convertCoordinate(buf.readInt()));
                position.setLongitude(convertCoordinate(buf.readInt()));
                position.setAltitude(buf.readShort()/ 10.0);
                position.setCourse((double) buf.readUnsignedShort());
                position.setSpeed(buf.readUnsignedShort() * 0.0539957);
               
                // Date and time
                Calendar time = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
                time.clear();
                time.set(Calendar.YEAR, 2000 + buf.readUnsignedByte());
                time.set(Calendar.MONTH, buf.readUnsignedByte() - 1);
                time.set(Calendar.DAY_OF_MONTH, buf.readUnsignedByte());
                time.set(Calendar.HOUR_OF_DAY, buf.readUnsignedByte());
                time.set(Calendar.MINUTE, buf.readUnsignedByte());
                time.set(Calendar.SECOND, buf.readUnsignedByte());
                position.setTime(time.getTime());
               
                // Accuracy
                int satellites = buf.readUnsignedByte();
                extendedInfo.set("satellites", satellites);
                position.setValid(satellites >= 3);
               
                position.setExtendedInfo(extendedInfo.toString());
                positions.add(position);
            }
           
            return positions;
        }
View Full Code Here

TOP

Related Classes of org.traccar.model.ExtendedInfoFormatter

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.