Package com.dtrules.session

Source Code of com.dtrules.session.DTState

/**
* Copyright 2004-2011 DTRules.com, Inc.
*
* See http://DTRules.com for updates and documentation for the DTRules Rules Engine 
*  
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
*  
*      http://www.apache.org/licenses/LICENSE-2.0 
*  
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License. 
**/

package com.dtrules.session;

import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Random;

import com.dtrules.decisiontables.ANode;
import com.dtrules.decisiontables.RDecisionTable;
import com.dtrules.entity.IREntity;
import com.dtrules.entity.REntityEntry;
import com.dtrules.infrastructure.RulesException;
import com.dtrules.interpreter.IRObject;
import com.dtrules.interpreter.RName;
import com.dtrules.xmlparser.XMLPrinter;

public class DTState {

    public Calendar        calendar;
    { // Work around for a Java Bug
      // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5045774
      //
        try {
            calendar = new GregorianCalendar();
        } catch (Throwable t) {
        }
    }

    private RDecisionTable currentTable;
    private String         currentTableSection;
    private int            numberInSection;
    private ANode          anode;                                    // The
                                                                      // current
                                                                      // Anode
                                                                      // under
                                                                      // execution.

    /**
     * The interpreter is a stack based interpreter. The implementation is much
     * like a Postscript Interpreter.
     *
     * The control stack is used to implement a stack frame for decision tables.
     * The control stack has no analog in a PostScript interpreter.
     *
     * The Entity stack is used to define the context for associating attributes
     * with values. This is much like the PostScript Dictionary Stack.
     *
     * The Data stack is used to pass data to operators and to return results
     * from operators.
     */

    private final int      stklimit     = 1000;

    IRObject               ctrlstk[]    = new IRObject[stklimit];
    IRObject               datastk[]    = new IRObject[stklimit];
    IREntity               entitystk[]  = new IREntity[stklimit];

    int                    ctrlstkptr   = 0;
    int                    datastkptr   = 0;
    int                    entitystkptr = 0;

    int                    frames[]     = new int[stklimit];
    int                    framestkptr  = 0;
    int                    currentframe = 0;

    final IRSession        session;

    public long            seed         = 0x711083186866559L;
    public Random          rand         = new Random(seed);
   
    /**
     * The default debugging printstream is Standard Out. The default error
     * printstream is Standard Out.
     */
    private XMLPrinter     out          = new XMLPrinter(System.out);
    private PrintStream    outPs        = System.out;
    private PrintStream    err          = System.out;

    public static final int DEBUG   = 0x00000001;
    public static final int TRACE   = 0x00000002;
    public static final int ECHO    = 0x00000004;
    public static final int VERBOSE = 0x00000008;

    private int             state   = 0;          // This is the Rules Engine
                                                  // State under which the engine
                                                  // is running. Values are
                                                  // defined by DEBUG, TRACE,
                                                  // etc.
   
    private HashMap<RName, Object> extendedState = new HashMap<RName,Object>();
   
    public PrintStream getErrorOut()            { return err;   }
    public PrintStream getDebugOut()            { return outPs; }
    public PrintStream getTraceOut()            { return outPs; }
    public XMLPrinter  getTraceXMLPrinter()     { return out; }

    /**
     * The Extended State returns an object that might be used to maintain state information
     * not provided for by the Graphics State, but is needed by extended or application
     * specific operators.
     * <br><br>
     * You should use your fully qualified class name as the key, for example:
     *    <br> <br>
     *    public static RName  extendedState = RName.getRName("com.dtrules.operators.polyoperators");
     *    <br> <br>
     *    setExtendedState(extendedState,new PolyState());
     *   
     * @param key
     * @return
     * @author paul snow
     **/  
    public Object getExtendedState(RName key){
        return extendedState.get(key);
    }
   
    /**
     * The Extended State returns an object that might be used to maintain state information
     * not provided for by the Graphics State, but is needed by extended or application
     * specific operators.
     * <br><br>
     * You should use your fully qualified class name as the key (though this isn't enforced), for example:
     *    <br> <br>
     *    public static RName  extendedState = RName.getRName("com.dtrules.operators.polyoperators");
     *    <br> <br>
     *    setExtendedState(extendedState,new PolyState());
     *   
     * @param key
     * @return
     * @author paul snow
     **/
    public void setExtendedState(RName key, Object object){
        extendedState.put(key,object);
    }
   
    /**
     * Set the output streams for debug and trace.
     */
    public void setOutput(OutputStream debugtrace, OutputStream error) {
        if (debugtrace != null) {
            outPs = new PrintStream(debugtrace);
            out = new XMLPrinter(outPs);
        }
        err = new PrintStream(error);
    }

    /**
     * Set the output streams for debug and trace.
     */
    public void setOutput(PrintStream debugtrace, PrintStream error) {
        outPs = debugtrace;
        out = new XMLPrinter(outPs);
        err = error;
    }

    /**
     * We always print the error stream. But this may not be true forever.
     *
     * @param s
     * @return
     */
    public boolean error(String s) {
        err.print(s);
        return true;
    }

    /**
     * Start the Trace
     */
    public void traceStart() {
        setState(TRACE);
        out.opentag("DTRulesTrace");
    }

    /**
     * Stop the trace
     *
     * @throws RulesException
     */
    public void traceEnd() throws RulesException {
        out.close();
        clearState(TRACE);
    }

    /**
     * Internal use. Begins a tagged trace section.
     *
     * @param tag
     * @param attribs
     */
    public void traceTagBegin(String tag, HashMap<String, Object> attribs) {
        if (testState(TRACE)) {
            out.opentag(tag, attribs);
        }
    }

    /**
     * Internal use. Begins a tagged trace section.
     *
     * @param tag
     */
    public void traceTagBegin(String tag) {
        if (testState(TRACE)) {
            out.opentag(tag);
        }
    }

    /**
     * Internal use. Begins a tagged trace section.
     *
     * @param tag
     * @param name1
     * @param value1
     */
    public void traceTagBegin(String tag, String name1, String value1) {
        if (testState(TRACE)) {
            out.opentag(tag, name1, value1);
        }
    }

    /**
     * internal use. Begins a tagged trace section.
     *
     * @param tag
     * @param name1
     * @param value1
     * @param name2
     * @param value2
     */
    public void traceTagBegin(String tag, String name1, String value1, String name2, String value2) {
        if (testState(TRACE)) {
            out.opentag(tag, name1, value1, name2, value2);
        }
    }

    /**
     * Internal use. Begins tagged section
     *
     * @param tag
     * @param name1
     * @param value1
     * @param name2
     * @param value2
     * @param name3
     * @param value3
     */
    public void traceTagBegin(String tag, String name1, String value1, String name2, String value2, String name3,
            String value3) {
        if (testState(TRACE)) {
            out.opentag(tag, name1, value1, name2, value2, name3, value3);
        }
    }

    /**
     * Internal use. Prints some information into the trace file.
     *
     * @param tag
     * @param body
     */
    public void traceInfo(String tag, String body) {
        if (testState(TRACE))
            out.printdata(tag, body);
    }

    /**
     * Internal use. Prints some information into the trace file.
     *
     * @param tag
     * @param name1
     * @param value1
     * @param body
     */
    public void traceInfo(String tag, String name1, String value1, String body) {
        if (testState(TRACE))
            out.printdata(tag, name1, value1, body);
    }

    /**
     * Internal use. Prints some information into the trace file.
     *
     * @param tag
     * @param name1
     * @param value1
     * @param name2
     * @param value2
     * @param body
     */
    public void traceInfo(String tag, String name1, String value1, String name2, String value2, String body) {
        if (testState(TRACE))
            out.printdata(tag, name1, value1, name2, value2, body);
    }

    /**
     * Internal use. Prints some information into the trace file.
     *
     * @param tag
     * @param name1
     * @param value1
     * @param name2
     * @param value2
     * @param name3
     * @param value3
     * @param body
     */
    public void traceInfo(String tag, String name1, String value1, String name2, String value2, String name3,
            String value3, String body) {
        if (testState(TRACE))
            out.printdata(tag, name1, value1, name2, value2, name3, value3, body);
    }

    /**
     * Internal use. Prints some information into the trace file.
     *
     * @param tag
     * @param name1
     * @param value1
     * @param name2
     * @param value2
     * @param name3
     * @param value3
     * @param name4
     * @param value4
     * @param body
     */
    public void traceInfo(String tag, String name1, String value1, String name2, String value2, String name3,
            String value3, String name4, String value4, String body) {
        if (testState(TRACE))
            out.printdata(tag, name1, value1, name2, value2, name3, value3, name4, value4, body);
    }

    /**
     * End the trace
     */
    public void traceTagEnd() {
        if (testState(TRACE)) {
            out.closetag();
        }
    }

    /**
     * Prints a string to the output file if DEBUG is on. If ECHO is set, then
     * the output is also echoed to Standard out. Returns true if it printed
     * something.
     */
    public boolean debug(String s) {
        if (testState(DEBUG)) {
            if (testState(ECHO) && outPs != System.out) {
                System.out.print(s);
            }
            out.printdata("dbg", s);
            return true;
        }
        return false;
    }

    /**
     * Prints the Data Stack, Entity Stack, and Control Stack to the debugging
     * output stream.
     */
    public void pstack() {
        if (testState(TRACE))
            return;
        try {
            out.opentag("pstack");

            out.opentag("datastk");
            for (int i = 0; i < ddepth(); i++) {
                out.printdata("ds", "depth", "" + i, getds(i).stringValue());
            }
            out.closetag();

            out.opentag("entitystk");
            for (int i = 0; i < ddepth(); i++) {
                out.printdata("es", "depth", "" + i, getes(i).stringValue());
            }
            out.closetag();

            out.closetag();
        } catch (RulesException e) {
            err.print("ERROR printing the stacks!\n");
            err.print(e.toString() + "\n");
        }
    }

    /**
     * Returns the count of the number of elements on the data stack.
     *
     * @return data stack depth
     */
    public int ddepth() {
        return datastkptr;
    }

    /**
     * Returns the element on the data stack at the given depth If there are 3
     * elements on the data stack, getds(2) will return the top element. A stack
     * underflow or overflow will be thrown if the index is out of range.
     */
    public IRObject getds(int i) throws RulesException {
        if (i >= datastkptr) {
            throw new RulesException("Data Stack Overflow", "getds", "index out of range: " + i);
        }
        if (i < 0) {
            throw new RulesException("Data Stack Underflow", "getds", "index out of range: " + i);
        }
        return datastk[i];
    }

    /**
     * Returns the element on the entity stack at the given depth If there are 3
     * entities on the entity stack, getes(2) will return the top entity. A
     * stack underflow or overflow will be thrown if the index is out of range.
     */
    public IREntity getes(int i) throws RulesException {
        if (i >= entitystkptr) {
            throw new RulesException("Entity Stack Overflow", "getes", "index out of range: " + i);
        }
        if (i < 0) {
            throw new RulesException("Entity Stack Underflow", "getes", "index out of range: " + i);
        }
        return entitystk[i];
    }

    /**
     * While the state holds the stacks, the Session holds changes to Entities
     * and other Rules Engine objects. On rare occasions we need to get our
     * session, so we save it in the DTState.
     *
     * @param rs
     */
    DTState(IRSession rs) {
        session = rs;
    }

    /**
     * Get Session
     *
     * @return the session assocaited with this state
     */
    public IRSession getSession() {
        return session;
    }

    /**
     * Returns the index of the Entity Stack.
     *
     * @return
     */
    public int edepth() {
        return entitystkptr;
    }

    /**
     * Pushes an IRObject onto the data stack.
     *
     * @param o
     * @throws RulesException
     */
    public void datapush(IRObject o) throws RulesException {
        if (datastkptr >= 1000) {
            throw new RulesException("Data Stack Overflow", o.stringValue(), "Data Stack overflow.");
        }
        datastk[datastkptr++] = o;
        if (testState(VERBOSE)) {
            traceInfo("datapush", "attribs", o.postFix(), null);
        }
    }

    /**
     * Pops an IRObject off the data stack and returns that object.
     *
     * @return
     * @throws RulesException
     */
    public IRObject datapop() throws RulesException {
        if (datastkptr <= 0) {
            throw new RulesException("Data Stack Underflow", "datapop()", "Data Stack underflow.");
        }
        IRObject rval = datastk[--datastkptr];
        datastk[datastkptr] = null;
        if (testState(VERBOSE)) {
            traceInfo("datapop", rval.stringValue());
        }
        return (rval);
    }

    /**
     * Pushes an entity on the entity stack.
     *
     * @param o
     * @throws RulesException
     */
    public void entitypush(IREntity o) throws RulesException {
        if (entitystkptr >= 1000) {
            throw new RulesException("Entity Stack Overflow", o.stringValue(), "Entity Stack overflow.");
        }
        entitystk[entitystkptr++] = o;
    }

    /**
     * Pops an Entity off of the Entity stack.
     *
     * @return
     * @throws RulesException
     */
    public IREntity entitypop() throws RulesException {
        if (entitystkptr <= 0) {
            throw new RulesException("Entity Stack Underflow", "entitypop", "Entity Stack underflow.");
        }
        IREntity rval = entitystk[--entitystkptr];
        entitystk[entitystkptr] = null;
        return (rval);
    }

    /**
     * Returns the nth element from the top of the entity stack (0 returns the
     * top element, 1 returns the 1 from the top, 2 the 2 from the top, etc.)
     *
     * @return
     * @throws RulesException
     */
    public IREntity entityfetch(int i) throws RulesException {
        if (entitystkptr <= i) {
            throw new RulesException("Entity Stack Underflow", "entityfetch", "Entity Stack underflow.");
        }
        IREntity rval = entitystk[entitystkptr - 1 - i];
        return (rval);
    }

    /**
     * Test to see if the given flag is set.
     *
     * @param flag
     * @return
     */
    public boolean testState(int flag) {
        return (state & flag) != 0;
    }

    /**
     * Clear the given flag (By and'ing the not of the flag into the state)
     */
    public void clearState(int flag) {
        state &= flag ^ 0xFFFFFFFF;
    }

    /**
     * Set the given flag by or'ing the flag into the state
     *
     * @param flag
     */
    public void setState(int flag) {
        state |= flag;
    }

    /**
     * Returns the current depth of the control stack.
     *
     * @return
     */
    public int cdepth() {
        return ctrlstkptr;
    }

    /**
     * Internal use. Pushes a frame onto the control stack from which local
     * variables can be allocated.
     *
     * @throws RulesException
     */
    public void pushframe() throws RulesException {
        if (framestkptr >= stklimit) {
            throw new RulesException("Control Stack Overflow", "pushframe", "Control Stack Overflow.");

        }
        frames[framestkptr++] = currentframe;
        currentframe = ctrlstkptr;
    }

    /**
     * Internal use. Pops a frame from the control stack, reclaiming storage
     * used by local variables.
     *
     * @throws RulesException
     */
    public void popframe() throws RulesException {
        if (framestkptr <= 0) {
            throw new RulesException("Control Stack Underflow", "popframe", "Control Stack underflow.");
        }
        ctrlstkptr = currentframe; // Pop off this frame,
        currentframe = frames[--framestkptr]; // Then set the currentframe back
                                              // to its previous value.
    }

    /**
     * Internal Use only. Get a value from a frame location.
     *
     * @param i
     * @return
     * @throws RulesException
     */
    public IRObject getFrameValue(int i) throws RulesException {
        if (currentframe + i >= ctrlstkptr) {
            throw new RulesException("OutOfRange", "getFrameValue", "");
        }
        return getcs(currentframe + i);
    }

    /**
     * Internal Use. Set a value within the stack frame.
     *
     * @param i
     * @param value
     * @throws RulesException
     */
    public void setFrameValue(int i, IRObject value) throws RulesException {
        if (currentframe + i >= ctrlstkptr) {
            throw new RulesException("OutOfRange", "getFrameValue", "");
        }
        setcs(currentframe + i, value);
    }

    /**
     * Internal use. Push an Object onto the control stack.
     *
     * @param o
     */
    public void cpush(IRObject o) {
        ctrlstk[ctrlstkptr++] = o;
    }

    /**
     * Pop the top element from the control stack and return it.
     *
     * @return
     */
    public IRObject cpop() {
        IRObject r = ctrlstk[--ctrlstkptr];
        ctrlstk[ctrlstkptr] = null;
        return r;
    }

    /**
     * Internal use. Pull a value off the control stack.
     *
     * @param i
     * @return
     * @throws RulesException
     */
    public IRObject getcs(int i) throws RulesException {
        if (i >= ctrlstkptr) {
            throw new RulesException("Control Stack Overflow", "getcs", "index out of range: " + i);
        }
        if (i < 0) {
            throw new RulesException("Control Stack Underflow", "getcs", "index out of range: " + i);
        }
        return ctrlstk[i];
    }

    /**
     * Set a value at a location on the control stack.
     *
     * @param i
     * @param v
     * @throws RulesException
     */
    public void setcs(int i, IRObject v) throws RulesException {
        if (i >= ctrlstkptr) {
            throw new RulesException("Control Stack Overflow", "setcs", "index out of range: " + i);
        }
        if (i < 0) {
            throw new RulesException("Control Stack Underflow", "getcs", "index out of range: " + i);
        }
        ctrlstk[i] = v;
    }

    /**
     * This method evalates a condition, or any other set of PostFix code that
     * produces a boolean value. The code must only add one element to the data
     * stack, and that element must have a valid boolean value.
     *
     * @param c
     *            -- Condition to execute
     * @return -- Returns the boolean value of c
     * @throws RulesException
     */
    public boolean evaluateCondition(IRObject c) throws RulesException {
        int stackindex = datastkptr; // We make sure the object only produces
                                     // one boolean.
        c.execute(this); // Execute the condition.
        if (datastkptr - 1 != stackindex) {
            throw new RulesException("Stack Check Exception", "Evaluation of Condition", "Stack not balanced");
        }
        return datapop().booleanValue();
    }

    /**
     * This method executes an action, or any other set of Postfix code. This
     * code can have side effects, but it cannot change the depth of the data
     * stack.
     *
     * @param c
     *            -- Object to execute
     * @throws RulesException
     */
    public void evaluate(IRObject c) throws RulesException {
        int stackindex = datastkptr;
        c.execute(this);
        if (datastkptr != stackindex) {
            throw new RulesException("Stack Check Exception", "Evaluation of Action", "Stack not balanced");
        }
    }

    /**
     * Looks up the entity stack for an instance of an entity with the given
     * entity name. If such an entity is on the entity stack (i.e. in the
     * current context) then this routine returns true, otherwise false. Note
     * that this routine doesn't care how many entities of that type are in the
     * context, but merely returns true if one of them is in the context.
     *
     * @param entity
     * @return
     */
    public boolean inContext(String entity) {
        return inContext(RName.getRName(entity));
    }

    /**
     * Looks up the entity stack for an instance of an entity with the given
     * entity name. If such an entity is on the entity stack (i.e. in the
     * current context) then this routine returns true, otherwise false. Note
     * that this routine doesn't care how many entities of that type are in the
     * context, but merely returns true if one of them is in the context.
     *
     * @param entity
     * @return
     */
    public boolean inContext(RName entity) {
        for (int i = 0; i < entitystkptr; i++) { // entity on the Entity Stack.
            IREntity e = entitystk[i];
            if (e.getName().equals(entity))
                return true;
        }
        return false;
    }

    /**
     * Looks up the entity stack for an Entity that defines an attribute that
     * matches the name provided. When such an Entity with an attribute that
     * matches the name is found, that Entity is returned. A null is returned if
     * no match is found, which means no Entity on the entity Stack defines an
     * attribute with a name that mathches the name provided.
     *
     * @param name
     */
    public IREntity findEntity(RName name) throws RulesException {
        RName entityname = name.getEntityName(); // If the RName does not spec
                                                 // an Enttiy Name
        if (entityname == null) { // then we simply look for the RName in each
            for (int i = entitystkptr - 1; i >= 0; i--) { // entity on the
                                                          // Entity Stack.
                IREntity e = entitystk[i];
                if (e.containsAttribute(name))
                    return e;
            }
        } else { // Otherwise, we insist that the Entity name
            for (int i = entitystkptr - 1; i >= 0; i--) { // match as well as
                                                          // insist that the
                                                          // Entity
                IREntity e = entitystk[i]; // have an attribute that matches
                                           // this name.
                if (e.getName().equals(entityname)) {
                    if (e.containsAttribute(name)) {
                        return e;
                    }
                }
            }
        }

        return null; // No matach found? return a null.
    }

    /**
     * Looks up the Entity Stack and returns the value for the given named
     * attribute.
     *
     * When getting data out of the rules Engine, it is useful to take string
     * values rather than RNames. This should never be done within the Rules
     * Engine where RNames should be the coin of the realm.
     *
     * This routine simply returns a null if an error occurs or if the name is
     * undefined.
     */
    public IRObject find(String name) {
        try {
            return find(RName.getRName(name));
        } catch (RulesException e) {
            return null;
        }
    }

    /**
     * Looks up the entity stack and returns the entity which defines the value
     * of the given attribute.
     *
     * When getting data out of the rules Engine, it is useful to take string
     * values rather than RNames. This should never be done within the Rules
     * Engine where RNames should be the coin of the realm.
     *
     * This routine simply returns a null if an error occurs or if the name is
     * undefined.
     */
    public IREntity findEntity(String name) {
        try {
            return findEntity(RName.getRName(name));
        } catch (RulesException e) {
            return null;
        }
    }

    /**
     * Looks up the entity stack for a match for the RName. When a match is
     * found, the value is returned. A null is returned if no match is found.
     *
     * @param name
     */
    public IRObject find(RName name) throws RulesException {
        IREntity entity = findEntity(name);
        if (entity == null)
            return null;
        return entity.get(name);
    }

    /**
     * Looks up the entity stack for a match for the RName. When a match is
     * found, the value is placed there and a true is returned. If no match is
     * found, def returns false.
     *
     * @param name
     * @param value
     */
    public boolean def(RName name, IRObject value, boolean protect) throws RulesException {

        RName entityname = name.getEntityName();

        for (int i = entitystkptr - 1; i >= 0; i--) {
            IREntity e = entitystk[i];
            if (!e.isReadOnly() && (entityname == null || e.getName().equals(entityname))) {
                REntityEntry entry = e.getEntry(name);
                if (entry != null && (!protect || entry.writable)) {
                    if (testState(TRACE)) {
                        out.printdata("def", "entity", e.postFix(), "name", name.stringValue(), value.postFix());
                    }

                    e.put(null, name, value);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Get the current Decision Table under execution.
     *
     * @return
     */
    public RDecisionTable getCurrentTable() {
        return currentTable;
    }

    /**
     * Internal Use. Set the current Decision Table under execution.
     *
     * @param currentTable
     */
    public void setCurrentTable(RDecisionTable currentTable) {
        this.currentTable = currentTable;
    }

    /**
     * Get the current Decision Table section, i.e. Condition, Action, Context,
     * etc.
     *
     * @return the currentTableSection
     */
    public String getCurrentTableSection() {
        return currentTableSection;
    }

    /**
     * Condition, Action, Context, etc.
     *
     * @param currentTableSection
     *            the currentTableSection to set
     */
    public void setCurrentTableSection(String currentTableSection, int number) {
        this.currentTableSection = currentTableSection;
        this.numberInSection = number;
    }

    /**
     * Condition number, context number, initial Action number, etc. -1 means
     * not set
     *
     * @return the numberInSection
     */
    public int getNumberInSection() {
        return numberInSection;
    }

    /**
     * Condition number, context number, initial Action number, etc. -1 means
     * not set
     *
     * @param numberInSection
     *            the numberInSection to set
     */
    public void setNumberInSection(int numberInSection) {
        this.numberInSection = numberInSection;
    }

    /**
     * Return the current ANode under execution.
     *
     * @return
     */
    public ANode getAnode() {
        return anode;
    }

    /**
     * Set the current ANode under execution.
     *
     * @param anode
     */
    public void setAnode(ANode anode) {
        this.anode = anode;
    }

}
TOP

Related Classes of com.dtrules.session.DTState

TOP
Copyright © 2018 www.massapi.com. 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.