I've written a domain and a test problem in PDDL, but apparently the graphplan implementation can't find a plan. Here's the domain:
(define (domain aperture)
(:requirements :strips :typing :negative-preconditions)
(:types
cube
hallway room - location
)
(:predicates
(at ?l - location)
(has ?c - cube)
(connected ?l1 - location ?l2 - location)
(in ?c - cube ?l - location)
)
(:action enter
:parameters (?h - hallway ?r - room)
:precondition (and (connected ?h ?r) (connected ?r ?h) (at ?h)
(not (at ?r)))
:effect (and (at ?r) (not (at ?h)))
)
(:action exit
:parameters (?r - room ?h - hallway)
:precondition (and (connected ?r ?h) (connected ?h ?r) (at ?r)
(not (at ?h)))
:effect (and (at ?h) (not (at ?r)))
)
(:action move
:parameters (?h1 ?h2 - hallway)
:precondition (and (connected ?h1 ?h2) (connected ?h2 ?h1)
(at ?h1) (not (at ?h2)))
:effect (and (at ?h2) (not (at ?h1)))
)
(:action pickup
:parameters (?c - cube ?l - location)
:precondition (and (at ?l) (not (has ?c)) (in ?c ?l))
:effect (and (has ?c) (not (in ?c ?l)))
)
(:action drop
:parameters (?c - cube ?l - location)
:precondition (and (at ?l) (has ?c) (not (in ?c ?l)))
:effect (and (not (has ?c)) (in ?c ?l))
)
)
and here's the problem:
(define (problem pb1)
(:domain aperture)
(:requirements :strips :typing)
(:objects h1 - hallway
h2 - hallway
h3 - hallway
r1 - room
c1 - cube)
(:init (at h1)
(connected h1 h2)
(connected h2 h1)
(connected h2 h3)
(connected h3 h2)
(connected h2 r1)
(connected r1 h2)
(in c1 r1)
)
(:goal (and
(has c1)
)
)
)
For this particular problem the set of states for the solution should be:
move(h1,h2)
enter(h2,r1)
pickup(c1,r1)
but, as I've said, the graphplan implementation that I'm using (graphplan) can't find any plan.
I was able to find a solution plan using strips. However, I had to tweak your domain slightly. Specifically, I changed the domain actions "pickup" and "drop" to replace the parameter type "location" with "room". With this change, I was able to find the following solution:
1. move h1 h2
2. enter h2 r1
3. pickup c1 r1
Maybe this could be the reason graphplan was unable to find a solution as well? Here are the modified domain and problem pddl files.
domain.pddl
(define (domain aperture)
(:requirements :strips :typing :negative-preconditions)
(:types
cube
hallway room - location
)
(:action enter
:parameters (?h - hallway ?r - room)
:precondition (and (connected ?h ?r) (connected ?r ?h) (at ?h)
(not (at ?r)))
:effect (and (at ?r) (not (at ?h)))
)
(:action exit
:parameters (?r - room ?h - hallway)
:precondition (and (connected ?r ?h) (connected ?h ?r) (at ?r)
(not (at ?h)))
:effect (and (at ?h) (not (at ?r)))
)
(:action move
:parameters (?h1 - hallway ?h2 - hallway)
:precondition (and (connected ?h1 ?h2) (connected ?h2 ?h1)
(at ?h1) (not (at ?h2)))
:effect (and (at ?h2) (not (at ?h1)))
)
(:action pickup
:parameters (?c - cube ?l - room)
:precondition (and (at ?l) (not (has ?c)) (in ?c ?l))
:effect (and (has ?c) (not (in ?c ?l)))
)
(:action drop
:parameters (?c - cube ?l - room)
:precondition (and (at ?l) (has ?c) (not (in ?c ?l)))
:effect (and (not (has ?c)) (in ?c ?l))
)
)
problem.pddl
(define (problem pb1)
(:domain aperture)
(:objects h1 - hallway
h2 - hallway
h3 - hallway
r1 - room
c1 - cube)
(:init (at h1)
(connected h1 h2)
(connected h2 h1)
(connected h2 h3)
(connected h3 h2)
(connected h2 r1)
(connected r1 h2)
(in c1 r1)
)
(:goal (and
(has c1)
)
)
)
Related
I am new to PDDL and AI planning area. I am actually creating a plan for a humanoid interacting with a human in a scenario. The scenario is as follows
Human enters the room (where robot and some objects are present in the room)
Robot detects human
Greets human after detecting
Then human asks for a cup
Robot assumes that human wants to drink coffee and responds to human on what time human took medication (there should be a gap of 1 hour for medication and coffee)
Human responds with the time
If the time matches to 1 hour gap, Robot responds that it will find cup
Robot detects the cup on the table
Robot responds to human that cup is on the table
Human picks the cup
Robot greets the human after detecting that the human is holding the cup
My PDDL domain file logic is as follows:
(define (domain sp)
(:requirements :typing :strips :adl)
(:types location agent item - object
robot human speak - agent
room - location
fruit cup table - item
clear polite listenatt - speak)
(:predicates
(at ?o - object ?l - location)
(detected_human ?p - human ?l - room)
(greeted ?r - robot ?p - human)
(detected_cup ?c - cup ?l - room)
(holded ?c - cup ?p - human)
(medichecked ?r - robot ?p - human)
(human_asked ?p - human)
(robot_responded ?r - robot ?cl - clear ?pl - polite)
)
(:action detect_human
:parameters (?p - human ?r - robot ?l - location)
:precondition (at ?r ?l)
:effect (detected_human ?p ?l)
)
(:action detect_cup
:parameters (?p - human ?c - cup ?r - robot ?l - location )
:precondition (and (detected_human ?p ?l)
(human_asked ?p)
(medichecked ?r ?p)
)
:effect (detected_cup ?c ?l)
)
(:action greet
:parameters (?r - robot ?p - human ?l - location ?pl - polite ?cl - clear)
:precondition (and (at ?r ?l) (detected_human ?p ?l))
:effect (and (greeted ?r ?p) (robot_responded ?r ?cl ?pl))
)
(:action hold
:parameters (?c - cup ?p - human ?l - location ?r - robot ?cl - clear ?pl - polite)
:precondition (and (detected_human ?p ?l)
(detected_cup ?c ?l)
(robot_responded ?r ?cl ?pl)
(medichecked ?r ?p)
)
:effect (holded ?c ?p)
)
(:action check_medi
:parameters (?p - human ?l - location ?r - robot)
:precondition (human_asked ?p)
:effect (medichecked ?r ?p)
)
(:action human_ask
:parameters (?p - human ?l - location ?r - robot)
:precondition (and (detected_human ?p ?l) (greeted ?r ?p))
:effect (human_asked ?p)
)
(:action robot_respond
:parameters (?p - human ?l - location ?r - robot ?cl - clear ?pl - polite ?c -cup)
:precondition (and (at ?r ?l) (detected_human ?p ?l))
:effect (and (when (human_asked ?p) (robot_responded ?r ?cl ?pl))
(when (detected_cup ?c ?l) (robot_responded ?r ?cl ?pl)))
)
)
My PDDL problem file is as follows:
(define (problem test12)
(:domain sp)
(:objects person0 - Human
pepper0 - Robot
apple - Fruit
cup0 - Cup
table0 - Table
room0 - Room
clear0 - Clear
polite0 - Polite)
(:init
(at pepper0 room0)
)
(:goal (holded cup0 person0)
)
currently it generates the following plan:
plan-found
(detect_human person0 pepper0 room0)
(greet pepper0 person0 room0 polite0 clear0)
(human_ask person0 room0 pepper0)
(check_medi person0 room0 pepper0)
(detect_cup person0 cup0 pepper0 room0)
(hold cup0 person0 room0 pepper0 clear0 polite0)
I wanted the expected plan to be something like this:
plan-found
(detect_human person0 pepper0 room0)
(greet pepper0 person0 room0 polite0 clear0)
(human_ask person0 room0 pepper0)
(robot_respond person0 polite0 clear0 room0)
(check_medi person0 room0 pepper0)
(robot_respond person0 polite0 clear0 room0)
(detect_cup person0 cup0 pepper0 room0)
(robot_respond person0 polite0 clear0 room0)
(hold cup0 person0 room0 pepper0 clear0 polite0)
I am not sure why the robot_respond action is never coming in the plan even though it is given in the effects and preconditions.
I appreciate if any direction on this problem. Its been more than a week I am struggling to get the logic correct.
It’s indispensable for the action ‘robot-response’? I mean it looks like you didn’t set any effects in action ‘robot-response’ as a condition for others or possibly the same predicate ‘(robot-responsed)’ can be satisfied in action ‘greet’?
I'm having trouble switching to an iterate version of some loop code:
(defun get-bound-?vars-1 (tree)
(loop for item in tree
when (consp item)
if (member (car item) '(exists forall doall))
nconc (delete-if-not #'?varp
(alexandria:flatten (second item)))
else nconc (get-bound-?vars item)))
My corresponding iterate translation:
(defun get-bound-?vars-2 (tree)
(iter (for item in tree)
(when (consp item)
(if (member (car item) '(exists forall doall))
(nconc (delete-if-not #'?varp
(alexandria:flatten (second item))))
(nconc (get-bound-?vars item))))))
As test case:
(defparameter *tree*
'(if (exists (?t transmitter)
(and (connecting ?t ?connector)
(bind (color ?t $hue))))
(if (not (exists ((?t1 ?t2) transmitter)
(and (connecting ?t1 ?connector)
(connecting ?t2 ?connector)
(bind (color ?t1 $hue1))
(bind (color ?t2 $hue2))
(not (eql $hue1 $hue2)))))
(activate-connector! ?connector $hue))))
Then loop OK:
(get-bound-?vars-1 *tree*) => (?T ?T1 ?T2)
But iterate not OK:
(get-bound-?vars-2 *tree*) => NIL
Thanks for any pointers.
In the driverlog domain in PDDL we have specified links and paths.
(define (domain driverlog)
(:requirements :typing)
(:types location locatable - object
driver truck obj - locatable
)
(:predicates
(at ?obj - locatable ?loc - location)
(in ?obj1 - obj ?obj - truck)
(driving ?d - driver ?v - truck)
(link ?x ?y - location) (path ?x ?y - location)
(empty ?v - truck)
)
And the way that it's defined in the problem is:
(define (problem DLOG-2-2-2)
(:domain driverlog)
(:objects
driver1 - driver
driver2 - driver
truck1 - truck
truck2 - truck
package1 - obj
package2 - obj
s0 - location
s1 - location
s2 - location
p1-0 - location
p1-2 - location
)
(:init
(at driver1 s2)
(at driver2 s2)
(at truck1 s0)
(empty truck1)
(at truck2 s0)
(empty truck2)
(at package1 s0)
(at package2 s0)
(path s1 p1-0)
(path p1-0 s1)
(path s0 p1-0)
(path p1-0 s0)
(path s1 p1-2)
(path p1-2 s1)
(path s2 p1-2)
(path p1-2 s2)
(link s0 s1)
(link s1 s0)
(link s0 s2)
(link s2 s0)
(link s2 s1)
(link s1 s2)
)
What's the difference between paths and links? I've tried to create a similar problem but omitting the path and I keep getting Unsolvable Problem. How can I properly define a path?
Thanks!
These are user-defined predicates:
(define (domain driverlog)
...
(:predicates
...
(link ?x ?y - location) (path ?x ?y - location)
...
)
)
so their semantics can be deduced by inspecting the corresponding model.
Both link and path are binary predicates that put in relation two locations, presumably when it's possible to move from one place to the other. This connection is unidirectional.
I read, from the source code, that the following actions are defined:
(:action DRIVE-TRUCK
:parameters
(?truck
?loc-from
?loc-to
?driver)
:precondition
(and (TRUCK ?truck) (LOCATION ?loc-from) (LOCATION ?loc-to) (DRIVER ?driver)
(at ?truck ?loc-from)
(driving ?driver ?truck) (link ?loc-from ?loc-to))
:effect
(and (not (at ?truck ?loc-from)) (at ?truck ?loc-to)))
(:action WALK
:parameters
(?driver
?loc-from
?loc-to)
:precondition
(and (DRIVER ?driver) (LOCATION ?loc-from) (LOCATION ?loc-to)
(at ?driver ?loc-from) (path ?loc-from ?loc-to))
:effect
(and (not (at ?driver ?loc-from)) (at ?driver ?loc-to)))
So it seems that two locations have a link if it is possible to DRIVE-TRUCK from one place to the other, and two locations have a path if it is possible to WALK from one place to the other.
There is really nothing else to say about it.
The reason why you keep getting UNSAT is because you placed the drivers and the trucks in two different locations:
(at driver1 s2)
(at driver2 s2)
(at truck1 s0)
(at truck2 s0)
Since the only connection among s0 and s2 is a link, the drivers cannot possibly reach the truck (and vice-versa). This is because a precondition of DRIVE-TRUCK is (driving ?driver ?truck), which is only set by BOARD-TRUCK if the driver is in the same location of the truck.
You can solve this issue by creating a path among s0 and s2. However, this seems to be against the naming convention of the model, which interconnects sX using links only. A better solution is to change the initial state and put a truck in the same location of each driver, or at least in a location that is reachable by the WALK action.
I'm new to the pddl. I need to find solution where a robot can put different objects in different destination cells. I'm using the software from http://www.fast-downward.org/. However, The problem is that my actions can't find the solution as required.
The restriction is that no 2 objects can be in the same room even if the robot is carrying an object.
attached: the domain file:
(define (domain gripper-strips)
(:predicates (ROOM ?x) ;iff x is a room
(OBJECT ?x) ;iff x is an onject
(HAND ?x) ;iff x is the robot's hand
(FREE ?x) ;iff x is the robot's hand and it is free of object
(ROBOT-AT ?x) ;iff x is a room and robot is located in x
(OBJECT-AT ?x ?y) ;iff x is an object + y is a room and x is located at y
(PATH ?x ?y) ;iff x and y are both room and there is no wall in-between
(CARRY ?x) ;iff x is an object and robot is carrying it
)
(:action MoveWithoutObject
:parameters (?room1 ?room2 ?hand)
:precondition (and (ROOM ?room1) (ROOM ?room1) (HAND ?hand) (not(=?room1 ?room2))
(FREE ?hand) (ROBOT-AT ?room1) (PATH ?room1 ?room2))
:effect (and (ROBOT-AT ?room2)
(not (ROBOT-AT ?room1)))
)
(:action MoveWithObject
:parameters (?room1 ?room2 ?obj ?hand)
:precondition (and (ROOM ?room1) (ROOM ?room2) (OBJECT ?obj) (HAND ?hand) (not(=?room1 ?room2))
(not (OBJECT-AT ?obj ?room1)) (not (OBJECT-AT ?obj ?room2))
(ROBOT-AT ?room1) (not(FREE ?hand))
(PATH ?room1 ?room2))
:effect (and (ROBOT-AT ?room2)
(not (ROBOT-AT ?room1)))
)
(:action Pickup
:parameters (?obj ?room ?hand)
:precondition (and (OBJECT ?obj) (ROOM ?room) (HAND ?hand)
(OBJECT-AT ?obj ?room) (ROBOT-AT ?room) (FREE ?hand) (not(CARRY ?obj)))
:effect (and (CARRY ?obj) (not (OBJECT-AT ?obj ?room)) (not (FREE ?hand)))
)
(:action Release
:parameters (?obj ?room ?hand)
:precondition (and (OBJECT ?obj) (ROOM ?room) (HAND ?hand)
(not(OBJECT-AT ?obj ?room)) (ROBOT-AT ?room) (not(FREE ?hand)) (CARRY ?obj))
:effect (and (OBJECT-AT ?obj ?room)
(not(CARRY ?obj))
(FREE ?hand))))
and the problem file:
(define (problem strips-gripper-x-8)
(:domain gripper-strips)
(:objects room1 room2 room3 room4 room5 room6 room7 room8 room9
object1 object2 object3
hand)
(:init (ROOM room1)(ROOM room2)(ROOM room3)(ROOM room4)(ROOM room5)(ROOM room6)(ROOM room7)(ROOM room8)(ROOM room9)
(OBJECT object1)(OBJECT objec21)(OBJECT object3)
(HAND hand)
(FREE hand)
(ROBOT-AT room1)
(OBJECT-AT object1 room6)(OBJECT-AT object2 room4)(OBJECT-AT object3 room7)
(PATH room1 room4)(PATH room4 room1)
(PATH room4 room5)(PATH room5 room4)
(PATH room5 room6)(PATH room6 room5)
(PATH room5 room8)(PATH room8 room5)
(PATH room6 room9)(PATH room9 room6)
(PATH room6 room3)(PATH room3 room6)
(PATH room3 room2)(PATH room2 room3)
(PATH room8 room7)(PATH room7 room8))
(:goal (and (OBJECT-AT object1 room7)(OBJECT-AT object2 room2)(OBJECT-AT object3 room9))))
Your approach is seemingly correct, but you have a couple of typos in your files that hinder the possibility of finding a solution.
problem.pddl:
change
(OBJECT object1)(OBJECT objec21)(OBJECT object3)
with
(OBJECT object1) (OBJECT object2) (OBJECT object3)
domain.pddl: change
change
(ROOM ?room1) (ROOM ?room1)
in action MoveWithoutObject with
(ROOM ?room1) (ROOM ?room2)
EDIT:
This escaped my first check since I didn't know the language in the first place and I assumed there was an universal quantification over the variables. You also need to fix MoveWithObject like this:
(:action MoveWithObject
:parameters (?room1 ?room2 ?obj1 ?obj2 ?obj3 ?hand)
:precondition (and (ROOM ?room1) (ROOM ?room2) (HAND ?hand) (not(=?room1 ?room2))
(OBJECT ?obj1) (OBJECT ?obj2) (OBJECT ?obj3)
(not (OBJECT-AT ?obj1 ?room1)) (not (OBJECT-AT ?obj1 ?room2))
(not (OBJECT-AT ?obj2 ?room1)) (not (OBJECT-AT ?obj2 ?room2))
(not (OBJECT-AT ?obj3 ?room1)) (not (OBJECT-AT ?obj3 ?room2))
(not (= ?obj1 ?obj2))
(not (= ?obj1 ?obj3))
(not (= ?obj2 ?obj3))
(ROBOT-AT ?room1) (not (FREE ?hand)) (PATH ?room1 ?room2))
:effect (and (ROBOT-AT ?room2)
(not (ROBOT-AT ?room1)))
)
Now the solver finds the following solution:
Solution found!
Actual search time: 2.23336s [t=4.41504s]
movewithoutobject room1 room4 hand (1)
movewithoutobject room4 room5 hand (1)
movewithoutobject room5 room6 hand (1)
pickup object1 room6 hand (1)
movewithobject room6 room3 object1 object2 object3 hand (1)
release object1 room3 hand (1)
movewithoutobject room3 room6 hand (1)
movewithoutobject room6 room5 hand (1)
movewithoutobject room5 room8 hand (1)
movewithoutobject room8 room7 hand (1)
pickup object3 room7 hand (1)
movewithobject room7 room8 object1 object2 object3 hand (1)
movewithobject room8 room5 object1 object2 object3 hand (1)
movewithobject room5 room6 object1 object2 object3 hand (1)
movewithobject room6 room9 object1 object2 object3 hand (1)
release object3 room9 hand (1)
movewithoutobject room9 room6 hand (1)
movewithoutobject room6 room3 hand (1)
pickup object1 room3 hand (1)
movewithobject room3 room6 object1 object2 object3 hand (1)
movewithobject room6 room5 object1 object2 object3 hand (1)
movewithobject room5 room8 object1 object2 object3 hand (1)
movewithobject room8 room7 object1 object2 object3 hand (1)
release object1 room7 hand (1)
movewithoutobject room7 room8 hand (1)
movewithoutobject room8 room5 hand (1)
movewithoutobject room5 room4 hand (1)
pickup object2 room4 hand (1)
movewithobject room4 room5 object1 object2 object3 hand (1)
movewithobject room5 room6 object1 object2 object3 hand (1)
movewithobject room6 room3 object1 object2 object3 hand (1)
movewithobject room3 room2 object1 object2 object3 hand (1)
release object2 room2 hand (1)
Plan length: 33 step(s).
Plan cost: 33
I used the following strategy for finding this solution, other strategies might find longer paths:
$ fast-downward.py --alias seq-opt-bjolp problem.pddl
I am currently experimenting with om and try to load external data for displaying it in a component.
My detail component:
(defn detail-component [app owner opts]
(reify
om/IInitState
(init-state [_]
(om/transact! app [:data] (fn [] "Test")))
om/IWillMount
(will-mount [_]
(go (let [foo (<! (fetch-something 1))]
(om/update! app #(assoc % :data foo))
)))
om/IRender
(render [_]
(dom/div nil
(dom/h1 nil "Foo")
(om/build another-component app)
)
))
)
(fetch-something is retrieving data from an API).
(defn another-component [{:keys [data]}]
(om/component
(.log js/console data)
(dom/h2 nil "Another component goes here")
(dom/h2 nil (data :description))
)
)
So to summarize, detail-component fetches data before mounting, attaches it to app and builds another-component. another-component then takes the description out of that data and displays it.
However when executing, I am getting Uncaught TypeError: Cannot read property 'call' of null at the point where I am trying to access the description. This indicates to me that at the point when another-component is getting built, the data is not there yet and it fails.
How can I tell om to build the app when data is available? Or do I have to build in some nil? checks?
Working example using state:
project.clj
(defproject asajax "0.0.1-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License - v 1.0"
:url "http://www.eclipse.org/legal/epl-v10.html"
:distribution :repo}
:min-lein-version "2.3.4"
:source-paths ["src/clj" "src/cljs"]
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/clojurescript "0.0-2371"]
[org.clojure/core.async "0.1.267.0-0d7780-alpha"]
[om "0.7.3"]
[com.facebook/react "0.11.2"]]
:plugins [[lein-cljsbuild "1.0.4-SNAPSHOT"]]
:hooks [leiningen.cljsbuild]
:cljsbuild
{:builds {:asajax
{:source-paths ["src/cljs"]
:compiler
{:output-to "dev-resources/public/js/asajax.js"
:optimizations :whitespace
:pretty-print true}}}})
core.cljs
(ns asajax.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[cljs.core.async :as async])
(:require-macros [cljs.core.async.macros :refer (go)]))
(enable-console-print!)
(def app-state (atom {}))
(defn another-component [{:keys [data]}]
(reify
om/IRenderState
(render-state [_ state]
(dom/div nil
;; (.log js/console data)
(dom/h2 nil "Another component goes here")
(dom/h2 nil (:description state))))))
(defn fetch-something [x]
(let [c (async/chan)]
(go
;; pretend a blocking call
;; wait for 2 sec
(<! (async/timeout 2000))
(>! c {:data "Roast peach & Parma ham salad"
:description "This is a lovely light starter with fantastic sweet, salty and creamy flavours"}))
c))
(defn detail-component [app owner opts]
(reify
om/IInitState
(init-state [_]
{:data "Test"})
om/IWillMount
(will-mount [_]
(go (let [foo (<! (fetch-something 1))]
;; (prn "GOT" foo)
(om/set-state! owner foo))))
om/IRenderState
(render-state [_ state]
(dom/div nil
(dom/h1 nil (:data state))
(om/build another-component app
{:state (om/get-state owner)})))))
(om/root
detail-component
app-state
{:target (. js/document (getElementById "app"))})
UPDATE2
Here is one using sablono and not using set-state!
Add to project.clj
[sablono "0.2.22"]
Full core.cljs
(ns asajax.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[cljs.core.async :as async]
[sablono.core :as html :refer-macros [html]])
(:require-macros [cljs.core.async.macros :refer (go)]))
(enable-console-print!)
(def app-state (atom {:data "Initial"
:description "Loading..."}))
(defn another-component [{:keys [description]}]
(om/component
(html
[:.description
[:h2 "Another component"]
[:h2 description]])))
(defn fetch-something [x]
(let [c (async/chan)]
(go
;; pretend a blocking call
;; wait for 2 sec
(<! (async/timeout 2000))
(>! c {:data "Roast peach & Parma ham salad"
:description "This is a lovely light starter with fantastic sweet, salty and creamy flavours"}))
c))
(defn detail-component [app owner opts]
(reify
om/IWillMount
(will-mount [_]
(go (let [foo (<! (fetch-something 1))]
;; (prn "GOT" foo)
(om/update! app foo))))
om/IRender
(render [_]
(html [:div
[:h1 (:data app)]
(om/build another-component app)
]))))
(om/root
detail-component
app-state
{:target (. js/document (getElementById "app"))})