Hey folks,

we're are now making ephysics API more stable, almost all the features
intended to go in are already implemented, so we are moving to the
next step:
adding support to physics on Edje.

There are many ways of doing this, so I'm sending a proposal with some
possibilities so we could discuss before we start to implement it.

Just to make it clearer. My proposal exposes a lot of ephysics,
something very complete
(for what I believe are valid use cases. Lot of things possible with
ephysics API are not exposed),
and that would require a lot of time to be completely done.
So, it will be implemented gradually, covering the main use cases first.

So initially would be possible to create a new world with a list of
bodies, with most properties set using ephysics default. Later we
would expose
some more relevant properties. Implement programs / scripts. Then
adding support to constraints, camera, etc etc...

But would be good to define what would be the better, complete scenario.

Thanks in advance,

======================================

PROPOSAL: SUPPORT PHYSICS ON EDJE

=== CHOICES ===
There are 3 main different ways to do it. The first one
is described in details above, and has some alternatives explained.
The other 2 can be understood with these details.

1) A single physics block that would be set per group, and all the rendered
   objects to be manipulated would be other groups.
2) A single physics block that would be set per group, and all the rendered
   objects to be manipulated would be other parts of this group.
3) A physics block to describe world, camera and constraints,
    that would be set per group. And extra physics blocks per part that
    should be associated to a body. Example:
    group {
        physics {
            world {
                ...
            }
        }
        parts {
            part {
                name: ..
                body_type: ...
                description {
                    ...
                    physics {
                        // body props
                    }
                }
            }
        }
    }

Regarding programs, there are three main choices:
1) Physics world, camera, constraints and bodies have states with these objects
   attributes. Using STATE_SET as already exists on Edje would be the way
   to change it. Bodies can handle actions that should be set only via
   scripts, like apply_impulse, apply_force, set_velocity ...
2) No specific physics ACTIONs. Everything should be set via scripts.
3) Another types of ACTION would be declared, like PHYSICS_IMPULSE,
   PHYSICS_FORCE, etc. So it could be used without scripts.

The main argument in using scripts is that hardly a user will want
just to set a hardcoded property. Usually it will be based on body's
and other parts current state, like using geometry or velocity, etc.
So it would be required to get properties, do some calculation, set to body.

PROGRAMS chapter exemplify it.

Initially I would go with choices 1) and 1), but I would like to see
what you think about it.


=== OVERVIEW ===
collections {
    ...
    group {
        ...
        parts {}
        physics {
            world {}
            camera {}
            bodies {
                body {}
                ...
            }
            constraints {
                constraint {}
                ...
            }
        }
        programs {}
        ...
}

=== PHYSICS ===
The "physics" block contains all the other blocks related to physics. Blocks
"world", "camera", "bodies" and "constraints" will be found inside it. Physics
only will be enabled if at least one "body" is listed on "bodies" block.

It should be included in group's block, since a physics world won't be shared
between groups.

=== WORLD ===
The "world" block can have one or more description blocks.
It's required to simulate physics between bodies.
Only one world can be declared per group.

Each "description" block is used to set all attributes required to configure a
physics world.

...
physics {
    world {
        name: "name";
        description {
            state: "description_name" INDEX;
            inherit: "another_description" INDEX;
            rel1 {
                ..
            }
            rel2 {
                ..
            }
            rate: 30;
            gravity: 0 294 0;
            running: 1;
            light {
                light: "part_name";
                all_bodies: 0;
            }
            simulation {
                fixed_time_step: 0.033;
                max_sub_steps: 3;
            }
            sleeping_time: 2.0;
            solver_iterations: 10;
            auto_delete {
                top: 1;
                bottom: 1;
                left: 1;
                right: 1;
                front: 0;
                back: 0;
            }
            stacking: 1;
        }
    }
    ...
}
...

---

name [world name]
    Define the name that refer to this world instance.

state [a name for the description] [an index]
    Sets a name used to identify a description inside the world.
    Multiple descriptions are used to declare different states of the same
    world, like "paused" or "inverse gravity".
    All states declarations are also coupled with an index number between 0.0
    and 1.0. All "world" block  must have at least one description named
    "default 0.0".

inherit [another description's name] [another description's index]
    When set, the description will inherit all the properties from the named
    description. The properties defined in this part will override the
    inherited properties, reducing the amount of necessary code for simple
    state changes. Note: inheritance in Edje is single level only.

rel1/rel2:
  Almost the same used for parts.
  Offset would have a third parameter, for z-axis.
  >>> ALTERNATIVE:
    render_geometry {
        position: [x] [y] [z]
        size [w] [h] [d]
    }
  Position relative to group geometry.
  <<<

rate [rate pixel / meter]
  Set rate between pixels on evas canvas and meters on physics world.
  It will be used by automatic updates of evas objects associated to
  physics bodies.
  By default rate is 30 pixels per meter.

gravity [x] [y] [z]
  Three double values defining the gravity vector. Each one is the component of
  this same vector over each axis. Its unit is Evas Coordinates per second ^ 2.
  The default value is 0, 294, 0 since we've a default rate of 30 pixels.

running [0 or 1]
  >>> It would be used to pause effects, not sure if would be useful here. <<<
  Takes a boolean value specifying if the world is paused or running.
  It's running by default (1).

light
  This block configure the light to be used in the scene.

  It will perform lighting calculations on the evas map applied on evas
  objects associated with all the bodies to have light applied over.

  There are two ways of setting a body to receive lighting. One is to simple
  set all the bodies to be affected, with all_bodies. The other is disabling
  it and setting "light" property on each "body" block which light should
  be applied.

  light [part's name]
    This sets the part that is used as the "light" for calculating the
    brightness (based on how directly the part's surface is facing the light
    source point). Like the perspective point part, the center point is used
    and zplane is used for the z position (0 being the zero-plane where all 2D
    objects normally live) and positive values being further away into the
    distance.

    The light part color is used as the light color (alpha not used for light
    color). The color2 color is used for the ambient lighting when calculating
    brightness (alpha also not used).

  all_bodies [0 or 1]
    If enabled it will apply light over all the bodies, not considering if
    they have "light" property set or unset. If disabled, light still can be
    applied at each body individually using body's properties.

  >>> ALTERNATIVE
  light {
      point {
        position: x y z
        color: r g b
      }
      ambient: rgb
      all_bodies: [0 | 1]
  }
  First version é really cool, since you can animate the light part. Also,
  it's already used by the "map" block.
  <<<

simulation
  <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>>
  It's a block used to set world simulation's fixed time step
  and max number of sub steps.

  Reducing the fixed time step improves collision quality, but impacts
  performance. Also, when this value is changed, the max number of sub
  steps need to be updated, otherwise the world may "lose time".
  The following equation must to be assured:

  time step < max_sub_steps * fixed_time_step;

  By default fixed time step is 1/60 seconds and the sub steps maximum amount
  is 3.

  fixed_time_step [time]
    Time of the internal simulation step, in seconds. Default is 1/60 seconds.

  max_sub_steps [steps]
    Integer used to specify the maximum number of steps that simulation
    is allowed to take at each simulation tick. Default value is 3.

sleeping_time [max sleeping time]
  A double determining the duration in seconds a body under the linear and
  angular threshold is supposed to be marked as sleeping. Default is 2.0;

solver_iterations [number of iterations used by constraint solver]
  <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>>
  It's a integer to set the number of iterations the constraint solver will
  will have for contact and joint constraints.

  The default value is set to 10. The greater number of iterations more
  quality and precise the result but with performance penalty.

  Hardly a value different from default will be required.

linear_slop [linear slop used by the solver]
  <<< MUST PROBABLY WILL BE DROPPED SINCE IT'S REALLY CORNER CASE >>>
  Linear slop on sequential impulse
  is used as a factor for penetration. The penetration will the manifold
  distance + linear slop.
  The default value is set to 0 with a small value results in a smoother
  stabilization for stacking bodies.

auto_delete
  This block lists all the boundaries of the world rendering area and should
  be used to enable or disable automatic deletion of bodies outside this
  area. All of them are disabled by default.

  top [0 or 1]
    Delete bodies when they're outside of render area by the top.

  bottom [0 or 1]
    Delete bodies when they're outside of render area by the bottom.

  right [0 or 1]
    Delete bodies when they're outside of render area by the right.

  left [0 or 1]
    Delete bodies when they're outside of render area by the left.

  front [0 or 1]
    Delete bodies when they're outside of render area by the front.

  back [0 or 1]
    Delete bodies when they're outside of render area by the back.

stacking [0 or 1]
   Enable or disable stacking based on bodies z coordinates.

   Evas objects will be restacked at each simulation tick. It's enabled by
   default, and disabling it can lead to wrong scenarios when movement
   on Z axis is enabled or when cloths are used.

   But disabling it can save performance, so if you won't face these
   scenarios, it safe to disable it, since no evas object will be moved to
   be below or above others.

=== CAMERA ===
The "camera" block can have one or more description blocks. Only one
"camera" block can be declared by group.

Camera is used to change the position of the frame to be rendered. By default
it matches world's rendering area. But it can be modified passing another
top-left point position, so another
region of the physics world will be rendered on the render area.
So if you have a scene larger than the render area, camera handling can
be very useful. Also it can be set to track a body.

Each "description" block is used to set all attributes required to configure a
camera.

...
physics {
    camera {
        name: "name";
        description {
            state: "description_name" INDEX;
            inherit: "another_description" INDEX;
            position: "part_name";
            track {
                body: "name";
                axis: 1 0;
            }
            perspective: "part_name";
        }
    }
    ...
}
...

---

name [camera name]
    Define the name that refer to this camera instance.

state [a name for the description] [an index]
    Sets a name used to identify a description inside the camera.
    Multiple descriptions are used to declare different states of the same
    camera, like "tracking a body" or "fixed at position X, Y, Z".
    All states declarations are also coupled with an index number between 0.0
    and 1.0. All "camera" block  must have at least one description named
    "default 0.0".

inherit [another description's name] [another description's index]
    When set, the description will inherit all the properties from the named
    description. The properties defined in this part will override the
    inherited properties, reducing the amount of necessary code for simple
    state changes. Note: inheritance in Edje is single level only.

position [another part's name]
    This sets the part that is used as the "central point of the camera".
    The center of this part will
    be used as the camera point, so size, color and visibility etc. are not
    relevant just center point is used.

perspective [another part's name]
    This sets the part that is used as the "perspective point" for giving a
    scene a "3d look". The perspective point should have a perspective section
    that provides zplane and focal properties. The center of this part will
    be used as the focal point, so size, color and visibility etc. are not
    relevant just center point, zplane and focal are used.

    >>> ALTERNATIVE:
    First version is already used on map, and make it easy to be moved
    around. But another version could be:
    perspective {
        distance: x y;
        z0: z;
        focal_distance: f;
        enabled: [0 | 1]
    }
    <<<

track
  It's a block used to set camera to track a body.

  When a body is tracked, the camera will move automatically, following
  this body. It will keeps the body centralized on rendered area.
  If it will be centralized horizontally and / or vertically depends
  if parameters horizontal and vertical are enabled.

  body [body's name]
    This sets the body to be tracked by the camera.

  axis [horizontal] [vertical]
    Two boolean values [0 or 1].

    If horizontal is enabled the tracked body will be horizontally centralized
    in the rendered area. Disabled by default.

    If vertical is enabled the tracked body will be vertically centralized
    in the rendered area. Disabled by default.

=== BODIES ===
The "bodies" block is used to list the bodies that compose the world.

A body is a representation of an object inside a physics world.

It can be customized in many ways, setting collision shape, material,
applying forces and velocity. It won't be visually represented per se.
It need to be associated to one or more (using faces) parts so they will
be rendered using it to be represented.

Each "description" block is used to set all attributes required to configure a
physics body.

...
physics {
    bodies {
        body {
            name: "name";
            type: RIGID_BOX;
            description {
                state: "description_name" INDEX;
                inherit: "another_description" INDEX;
                source: "group's name";
                material: IRON;
                density: 80.3;
                mass: 66.6;
                rel1 {
                    ..
                }
                rel2 {
                    ..
                }
                use_part_geometry: 0;
                rotation: 1 1 0 0;
                restitution: 0.7;
                friction: 0.45;
                damping: 0.4 20;
                sleeping_threshold: 0.5 0.5;
                collision_groups: "group1" "group2" ...;
                velocity {
                    linear: 10.2 1.3 0;
                    angular: 0 0 2.2;
                }
                forces {
                    central: 0 2.5 5;
                    torque: 0 1.3 0;
                }
                faces {
                    face {
                        face: BOX_RIGHT;
                        source: "group's name";
                    }
                    face {
                        face: BOX_LEFT;
                        source: "group's name";
                    }
                    ...
                }
                movement_freedom {
                    linear: 1 1 0;
                    angular: 0 0 1;
                }
                light_on: 1;
                backface_cull: 0;
                hardness: 1.0; // for soft bodies and cloths only
                anchor { // for cloths only
                    body: "name";
                    side: ANCHOR_LEFT;
                    nodes: 10 12 14 16 ...;
                }
            }
        }
        body {}
        ...
    }
    ...
}
...

---

name [body name]
    Define the name that refer to this body instance.

type [TYPE]
    Set the type (all caps) from among the available body's shape types.
    It's set to RIGID_BOX by default. Valid types:
       * RIGID_BOX
       * RIGID_CIRCLE
       * SOFT_BOX
       * SOFT_CIRCLE
       * CLOTH
       * BOUNDARY_TOP
       * BOUNDARY_BOTTOM
       * BOUNDARY_RIGHT
       * BOUNDARY_LEFT
       * BOUNDARY_FRONT
       * BOUNDARY_BACK

state [a name for the description] [an index]
    Sets a name used to identify a description inside the body.
    Multiple descriptions are used to declare different states of the same
    body, like "moving", "rotating" or "heavier".
    All states declarations are also coupled with an index number between 0.0
    and 1.0. All "body" block must have at least one description named
    "default 0.0".

inherit [another description's name] [another description's index]
    When set, the description will inherit all the properties from the named
    description. The properties defined in this part will override the
    inherited properties, reducing the amount of necessary code for simple
    state changes. Note: inheritance in Edje is single level only.

source [group's name]
    This sets the group that is used as the object representing the physics
    body. A physics body isn't rendered per se.
    >>> ALTERNATIVE
        Using parts is possible too, but since ephysics sets a map
        and changes position, it could be harder to implement and
        a bit more error prone. In cases of mapping wanted, the
        user would need to set the part as group type, and
        use map inside this group.
        The negative point of using groups is that declaring groups is more
        verbose. But a macro could be used. The positive is that it could
        be set to many bodies.

    part [part's name]
        This sets the part that is used as the object representing the physics
        body. A physics body isn't rendered per se.
    <<<

material [MATERIAL]
    Set the type (all caps) from among the available material types, it's set
    to CUSTOM by default.

    Each material has specific properties to be
    applied on the body, as density, friction and restitution.

    Valid types:
       * CUSTOM
       * CONCRETE
       * IRON
       * PLASTIC
       * POLYSTYRENE
       * RUBBER
       * WOOD

density [material's density]
    The density of a material is its mass per unit volume.

    It will set the body mass considering its volume. While a density is set,
    resizing a body will always recalculate its mass.

    When a mass is explicitely set the density will be unset.

mass [mass in kg]
    Double value used to set inertial mass of the body.

    It is a quantitative measure of an object's resistance to the change of
    its speed. If mass is set to 0 the body will have infinite mass,
    so it will be immovable, static.

rel1/rel2:
  Almost the same used for parts.
  Offset would have a third parameter, for z-axis.
  >>> ALTERNATIVE:
    geometry {
        use_part_geometry: [0 | 1]
        position: [x] [y] [z]
        size [w] [h] [d]
    }
  Position relative to group geometry.
  <<<

use_part_geometry [0 or 1]
    If enabled, rel1 / rel2 will be discarded and the body will be set
    with the same geometry set to the part specified in "part" property.
    If this part is resized later, body will be resized together.

rotation [w x y z]
    Set body's rotation using quaternion representation.

restitution [coefficient of restitution]
    The coefficient of restitution is proportion between speed after and
    before a collision. It's 0 by default.

    COR = relative speed after collision / relative speed before collision

    * elastically collide for COR == 1;
    * inelastically collide for 0 < COR < 1;
    * completely stop (no bouncing at all) for COR == 0.

friction [coefficient of friction]
    Friction is used to make objects slide along each other realistically.

    The friction parameter is usually set between 0 and 1, but can be any
    non-negative value. A friction value of 0 turns off friction and a value
    of 1 makes the friction strong.

    By default friction value is 0.5 and simulation results will be better
    when friction in non-zero.


damping [linear_damping] [angular_damping]
    Damping(linear and angular) values are applied to body's linear and angular
    velocity.

    By applying a bodies damping factor the user will face a velocity reduction,
    with a force applied to it - "like" air resistance. The force is applied to
    slow it down.

sleeping_threshold [linear_threshold] [angular_threshold]
    These factors are used to determine whenever a rigid body is supposed to
    increment the sleeping time. Linear threshold is measured in Evas
    coordinates per second and angular threshold is measured in degrees
    per second.

    After every tick the sleeping time is incremented, if the body's linear and
    angular speed is less than the respective thresholds the sleeping time is
    incremented by the current time step (delta time).

    Reaching the max sleeping time the body is marked to sleep, that means
    the rigid body is to be deactivated.

collision_groups ["name_of_group_1"]  ["name_of_group_2"] ...
    If not added to any group the body will collide against any other body.
    Otherwise this body will collide only against those in the same groups.
    Groups don't need to be previously declared anywhere. They are
    created on demand when used by a body.

    <<< ALTERNATIVE
        collision_groups {
            group: "name_of_group_1";
            group: "name_of_group_2";
            group: "name_of_group_3";
            ...
        }
    >>>

velocity
    <<< PROBABLY IT WILL BE BETTER TO JUST SET IT VIA EMBRYO
        IT DOESN'T FIT WELL IN STATE >>>
    It's a block used to set body's angular and linear initial velocity.
    This velocity will be set when this body state is set, but will
    be increased or decreased considering many other properties and
    interactions with the world and other bodies or constraints.
    That's why it's said to be the INITIAL velocity. It's not necessarily
    constant.

    linear [x] [y] [z]
        Three double values for each component of linear velocity.
        Unit for linear velocity is Evas coordinates per second.

    angular [x] [y] [z]
        Three double values for angular velocity around each axis.
        Unit for angular velocity is degrees per second.

forces
    <<< PROBABLY IT WILL BE BETTER TO JUST SET IT VIA EMBRYO
        IT DOESN'T FIT WELL IN STATE >>>
    It's a block used to set forces applied over body.
    Force is measured in kg * p / s / s.

    Force is the product of mass and acceleration. So, keeping the mass
    fixed, when force is applied acceleration will change, and consequently,
    velocity will gradually be changes.

    Force = mass * acceleration

    Final velocity = initial velocity + acceleration * time

    central [x] [y] [z]
        Three double values for each component of the force to be applied
        in the center of the body. It won't produce torque.

    torque [x] [y] [z]
        A torque will be applied over the body to change the angular
        acceleration of this body. It will leads to a change on angular
        velocity over time.

        Three double values for torque to be applied around each axis.
        Negative values will accelerate it on counter clockwise rotation.

faces
    The "faces" block is used to list the faces that compose the body.
    Each face is described by a "face" block, that associates a part
    to a specific face of the body's shape.

    face [FACE]
        Set the face (all caps) from among the available body's shape faces.
        Valid faces:
            * BOX_MIDDLE_FRONT,
            * BOX_MIDDLE_BACK,
            * BOX_FRONT,
            * BOX_BACK,
            * BOX_LEFT,
            * BOX_RIGHT,
            * BOX_TOP,
            * BOX_BOTTOM,
            * CYLINDER_MIDDLE_FRONT,
            * CYLINDER_MIDDLE_BACK,
            * CYLINDER_FRONT,
            * CYLINDER_BACK,
            * CYLINDER_CURVED,
            * CLOTH_FRONT,
            * CLOTH_BACK,

    source [group's name]
        This sets the group that is used as the object representing the physics
        body face.
        >>> ALTERNATIVE - the same explained above for body source <<<

movement_freedom
    The "movement_freedom" block consists of two blocks to describe all
    the allowed movements for a body.
    It's set by default to allow just 2D movement (linear moves on
    x and y axis and rotations on x-y plane).

    linear [x-axis] [y-axis] [z-axis]
        Block "linear" can be used to allow linear movements in the three
        axes. Allowed values are 0 or 1.
        Axes x and y are enabled by default.

    angular [x-axis] [y-axis] [z-axis]
        Block "angular" can be used to allow angular movements around the three
        axes. Allowed values are 0 or 1.
        Z axis is enabled by default.

light_on [0 or 1]
    Set body to be affected by world's light or not.
    It won't be respected if world's property "all_bodies" is enabled.

backface_cull [0 or 1]
    This enables backface culling (when the rotated part that normally faces
    the camera is facing away after being rotated etc.).
    This means that the object will be hidden when "backface culled".

hardness: [hardness]
    The hardness is set with a double value (0.0 - 1.0), defining
    how the soft body is supposed to deform.
    Its default is set to 1.0. The soft body mass will also interfere on soft
    body deformation, so bare in mind that the bodies mass must also be changed
    to have different deformation results.

    Valid values vary from 0.0 to 1.0. Only works on soft bodies and cloths.

anchor
    Anchors are used to fix one or more cloth's nodes.

    body ["body's name"]
        The body to be anchored to.

    side [ANCHOR_SIDE]
        Set the side (all caps) from among the available cloth's sides.
        All the nodes part of the specified side of the cloth will be anchored
        to body. That is, all the nodes in the informed "edge".

        Valid sides:
            * LEFT
            * RIGHT
            * TOP
            * BOTTOM

     nodes [n1] [n2] [n3] ...
        Instead of using sides it's possible to specify nodes by index to
        anchor them.
        <<< ALTERNATIVE
        nodes {
            node: n1;
            node: n2;
            node: n3;
            ...
        }
        >>>

=== CONSTRAINTS ===
>> Constraints API is going to be heavily modified in the next days, so it's
just illustrative. <<

The "constraints" block is used to list the constraints that compose the world.

Constraints can be used to limit bodies movements, between bodies or
between bodies and the world. Constraints can limit movement angle,
translation, or work like a motor.

Each "description" block is used to set all attributes required to configure a
physics constraint.

...
physics {
    constraints {
        constraint {
            name: "name";
            type: POINT_TO_POINT;
            description {
                state: "description_name" INDEX;
                inherit: "another_description" INDEX;
                anchor {
                    p1 {
                        body: "name";
                        position: x y z;
                    }
                    p2 {
                        body: "name";
                        position: x y z;
                    }
                }
                limit {
                    linear {
                        left_x: value;
                        right_x: value;
                        under_y: value;
                        ...
                    }
                    angular {
                        x: value;
                        y: value;
                        z: value;
                    }
                }
            }
        }
        constraint {}
        ...
    }
    ...
}
...

---

name [constraint name]
    Define the name that refer to this constraint instance.

type [TYPE]
    Set the type (all caps) from among the available constraint types, it's set
    to POINT_TO_POINT by default. Valid types:
       * POINT_TO_POINT
       * SLIDER

state [a name for the description] [an index]
    Sets a name used to identify a description inside the constraint.
    All states declarations are also coupled with an index number between 0.0
    and 1.0. All "constraint" block  must have at least one description named
    "default 0.0".

inherit [another description's name] [another description's index]
    When set, the description will inherit all the properties from the named
    description. The properties defined in this part will override the
    inherited properties, reducing the amount of necessary code for simple
    state changes. Note: inheritance in Edje is single level only.

anchor
    TODO

limit
    TODO

=== PROGRAMS (related to physics) ===

...
group {
    programs {
        program {
            name: "change_physics_state";
            action: STATE_SET "physics_state_name" 0.0;
            transition: ACCEL 1;
            target: "world";
            target: "camera";
            target: "body1";
            target: "body2";
            target: "constraint1";
        }
        program {
            name: "body_actions";
            script {
                apply_impulse(BODY:"body1", 10, -3.2, 0.0);
                set_velocity(BODY:"body2", 0, 10, 0.0);
                apply_force(BODY:"body3", -5, 0, 0);
                get_geometry(PART:"button", &x, &y, &w, &h);
                get_cursor(&px, &py);
                apply_impulse(BODY:"body3", (px - x), 100, 0);
            }
        }
    }
}

scripts API:
    body_set_velocity
    body_get_velocity
    body_stop

    body_apply_impulse
    body_apply_central_impulse
    body_apply_torque_impulse

    body_apply_force
    body_apply_central_force
    body_apply_torque
    body_clear_forces

    <<< ALTERNATIVE
        Just make everything accessible via embryo.
        Drop states completely.
    >>>


-- 
Bruno Dilly
Lead Developer
ProFUSION embedded systems
http://profusion.mobi

------------------------------------------------------------------------------
Monitor your physical, virtual and cloud infrastructure from a single
web console. Get in-depth insight into apps, servers, databases, vmware,
SAP, cloud infrastructure, etc. Download 30-day Free Trial.
Pricing starts from $795 for 25 servers or applications!
http://p.sf.net/sfu/zoho_dev2dev_nov
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel

Reply via email to