Commit Graph

538 Commits

Author SHA1 Message Date
Wenlong Lu
24f5b819cf fix a memory leak 2018-10-02 10:58:23 -07:00
erwincoumans
8aff1fbd49 removed flags from loadURDF command. The flags are already available in m_data->m_flags in BulletUrdfImporter.cpp 2018-10-02 08:39:47 -07:00
erwincoumans
c9bd997acf
Merge pull request #1910 from WenlongLu/create_status
Two minor updates for PhysicsServerCommandProcessor
2018-10-01 18:53:13 -07:00
Wenlong Lu
085984f003 update complete status for removing collision shape 2018-10-01 17:54:23 -07:00
Wenlong Lu
167520a5e6 pass plane constant 2018-10-01 17:38:24 -07:00
Erwin Coumans
42ae4e81a8 apply clang-format (on Mac, slightly different than running it on Windows) 2018-09-30 11:43:57 -07:00
erwincoumans
5bcd43711a PyBullet OpenGL/EGL hardware getCameraImage: use glViewport to reduce the glReadPixels calling cost dramatically for small images
PyBullet Allow OpenGL/EGL hardware to render segmentation mask. Use pybullet.ER_SEGMENTATION_MASK_OBJECT_AND_LINKINDEX or pybullet.ER_SEGMENTATION_MASK
PyBullet.removeBody fix indexing bug (use foundIndex, not i)
PyBullet bump up version to 2.2.3
2018-09-30 07:10:40 -07:00
mbennice
6655bd60c8 Update stb_image.h import 2018-09-27 14:09:00 -07:00
mbennice
7485999254 Clang Format Change 2018-09-27 10:00:39 -07:00
mbennice
30d4c4136a Piping through the flag to parse sensors 2018-09-27 09:49:59 -07:00
Julian Viereck
219dfc757a Adding support for lateral friction to getContactPoints() 2018-09-24 10:03:43 -04:00
erwincoumans
ab8f16961e Code-style consistency improvement:
Apply clang-format-all.sh using the _clang-format file through all the cpp/.h files.
make sure not to apply it to certain serialization structures, since some parser expects the * as part of the name, instead of type.
This commit contains no other changes aside from adding and applying clang-format-all.sh
2018-09-23 14:17:31 -07:00
erwincoumans
b73b05e9fb add getClosestPoints.py example.
allow to perform a getClosestPoints query with a collisionShape and world transform (position, orientation) that isn't part of the world.
(use createCollisionShape to create it)
add optional removeCollisionShape, for collision shapes only used in a query (and not used to create a body)
2018-09-22 14:18:21 -07:00
erwincoumans
cdf8c908ad add getClosestPoints.py example.
allow to perform a getClosestPoints query with a collisionShape and world transform (position, orientation) that isn't part of the world.
(use createCollisionShape to create it)
2018-09-22 13:17:09 -07:00
erwincoumans
e6d74580c1 add single step rendering feature:
while (1):
    stepSimulation()
    pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_SINGLE_STEP_RENDERING, 1)

disable single step using
pybullet.configureDebugVisualizer(pybullet.COV_ENABLE_SINGLE_STEP_RENDERING, 0)
2018-09-14 17:17:11 -07:00
erwincoumans
9553892770 PyBullet / BulletRobotics:
Implement collisionFilterPlugin, use setCollisionFilterPair to enable or disable collision detection between specific pairs of objects.
Also, expose setCollisionFilterGroupMask as PyBullet API and in urdf using the tag <collision group="1" mask="2"/>.
See examples/pybullet/examples/collisionFilter.py for an example.
PyBullet default: Lower the warmstarting factor, for maximal coordinates rigid bodies for more stable simulation.
Add btCollisionWorld::refreshBroadphaseProxy to easier recreate the broadphase proxy without adding/removing objects to the world.
2018-09-12 19:30:49 -07:00
erwincoumans
9698c3d600 PyBullet setup.py: only enable BT_USE_EGL on Linux, but allow to run the eglPlugin on Windows and Mac as well (using their default opengl window).
postpone the 'loadPlugin' for static eglPlugin, so that the init and exit happen in the same thread.
When you don't call unloadPlugin, the program may crash when exiting in SHARED_MEMORY_SERVER mode.
2018-09-09 21:08:47 -07:00
erwincoumans
7369005402 pybullet, use eglPlugin statically instead of dynamic loading an Extension -DSTATIC_EGLRENDERER_PLUGIN
Fix compile errors of pybullet on Windows.
2018-09-09 15:23:26 -07:00
erwincoumans
0efc67841d allow pybullet to connect to GRPC server. (need to use flag --enable_grpc in premake build system)
add grpcPlugin, it can work in GUI, SHARED_MEMORY_SERVER, DIRECT and other modes.
example script to start server from pybullet:
import pybullet as p
p.connect(p.GUI)
#if statically linked plugin
id = p.loadPlugin("grpcPlugin")
#dynamics loading the plugin
#id = p.loadPlugin("E:/develop/bullet3/bin/pybullet_grpcPlugin_vs2010_x64_debug.dll", postFix="_grpcPlugin")

#start the GRPC server at hostname, port
if (id>=0):
	p.executePluginCommand(id, "localhost:1234")

Only in DIRECT mode, since there is no 'ping' you need to call to handle RCPs:
numRPC = 10
while (1):
	p.executePluginCommand(id, intArgs=[numRPC])
2018-09-05 17:58:14 -07:00
erwincoumans
23e84ca9b6 more work on proto/pybullet.proto 2018-09-01 13:49:56 -07:00
erwincoumans
4f7dfc2069 Add preliminary GRPC server for PyBullet and BulletRobotics.
Will add GRPC client and PyBullet GRPC server plugin.
Will cover most/all SharedMemoryCommand/SharedMemoryStatus messages.
Run the server, then test using the pybullet_client.py
2018-08-29 21:12:13 -07:00
Erwin Coumans
72c48870b0 after picking in a multibody demo, allow sleeping for rigid bodies 2018-08-26 18:07:28 -07:00
Erwin Coumans
186ddb81d8 fix tab/space issue in Python file
fix determinism issue introduced in previous commit
2018-08-26 17:17:42 -07:00
Erwin Coumans
6ab6cf0bdb test if different broadphase maintains determinism 2018-08-26 16:49:17 -07:00
Erwin Coumans
ff43cea263 Fix some deactivation issues with btMultiBodyDynamicsWorld, should also improve performance for PyBullet with larger worlds
(even when sleeping is disabled, islands are split)
2018-08-26 16:14:36 -07:00
Erwin Coumans
61b7591b8e expose choice of contraint solver in PyBullet, with switchConstraintSolver example 2018-08-23 23:04:17 -07:00
Erwin Coumans
15e831ab99 revert default linear slop, need to handle restitution separately 2018-08-09 16:49:25 -07:00
erwincoumans
961d8adad1
Merge pull request #1806 from erwincoumans/master
prepare build system(s) for collisionFilterPlugin
2018-08-03 17:43:13 -07:00
Tigran Gasparian
d93980f89f Adds a simulation stepped notification
This notification is called when the simulation is stepped, regardless
of whether any objects have moved.
2018-08-01 17:49:58 +02:00
Erwin Coumans
2cab56d6ef prepare build system(s) for collisionFilterPlugin 2018-07-27 15:48:24 +02:00
erwincoumans
8b27a7311c
Merge pull request #1801 from RanTig/TickPlugins
Notify plugins on certain events (e.g. body added).
2018-07-27 14:58:55 +02:00
Erwin Coumans
a696bd6a46 fix memory leak reported in Issue #1800
avoid access to array elements outside of range
2018-07-25 19:59:29 +02:00
Tigran Gasparian
35a55b2056 Changes tickPlugins to reportNotifications and only calls the processNotifications function on the plugins when there are actually notifications available. tickPlugins will to into a separate PR. 2018-07-25 14:47:34 +02:00
Tigran Gasparian
c59afb88c4 Notify plugins on certain events (e.g. body added).
This also adds a periodic tick function to plugins, giving them periodically control over the simulation thread, even when the simulation is paused.
2018-07-24 14:12:16 +02:00
erwincoumans
3d5c921495
Merge pull request #1782 from RanTig/userdata
Changes UserData to use global identifiers and makes linkIndex optional.
2018-07-09 11:36:51 +02:00
Erwin Coumans
127b82ec1b expose texture unique id after loading URD file, so you can restore to the original texture after changing it to a custom texture. See also getTextureUid.py example. 2018-07-08 11:23:12 +02:00
Tigran Gasparian
8a6db042de Removes int initializer in SharedMemoryUserDataHashKey, changes '>>' into '> >' for nexted templates. 2018-07-04 14:25:48 +02:00
Tigran Gasparian
9c7aa3a863 Changes UserData to use global identifiers and makes linkIndex optional.
This removes the need to specify the body id/link index when retrieving a user data entry.
Additionally, user data can now optionally be set to visual shapes as well.

The following public pybullet APIs have changed (backwards incompatible)
addUserData and getUserDataId
  Makes linkIndex parameter optional (default value is -1)
  Adds optional visualShapeIndex parameter (default value is -1)

getUserData and removeUserData
  Removes required parameters bodyUniqueId and linkIndex

getNumUserData
  Removes required bodyUniqueId parameter

getUserDataInfo
  Removes required linkIndex parameter
  Changes returned tuple from (userDataId, key) to (userDataId, key, bodyUniqueId, linkIndex, visualShapeIndex)
2018-07-03 17:45:19 +02:00
Erwin Coumans
21b089b0d7 Merge remote-tracking branch 'bp/master' 2018-06-26 08:57:44 -07:00
YunfeiBai
812c229736 Remove the pdController when maxForce = 0 2018-06-24 17:06:16 -07:00
erwincoumans
49b0ec08e1 PyBullet: allow to replace existing debug lines in addUserDebugLine through the replaceItemUniqueId argument
See batchRayCast.py for example usage
2018-06-22 16:47:20 -07:00
Tigran Gasparian
618e3230a4 Fix: Use function context reference instead of value 2018-06-22 20:41:02 +02:00
Tigran Gasparian
b84eb8af74 Several fixes for the parallel raycasts
- Limits the maximum number of threads to 64, since btThreadSupportPosix
and btThreadsupportWin32 don't support more than 64 bits at this moment,
due to the use of UINT64 bitmasks. This could be fixed by using
std::bitset or some other alternative.
- Introduces a threadpool class, b3ThreadPool, which is a simple wrapper
around btThreadSupportInterface and uses this instead of the global task
scheduler for parallel raycasting. This is actually quite a bit faster
than the task scheduler (~10-15% in my tests for parallel raycasts),
since the advanced features (parallelFor) are not necessary for the
parallel raycasts.
- Puts 16*1024 of MAX_RAY_INTERSECTION_MAX_SIZE_STREAMING in
parentheses, since it otherwise causes problems with other operators
of equal precedence and introduces a smaller constant for Apple targets.
- Refactors the parallel raycasts code and adds some more profiling.
2018-06-19 18:41:42 +02:00
erwincoumans
42c9d9aa3c lazy creation of batch scheduler, it causes issues with the physics. 2018-06-16 13:59:03 -07:00
erwincoumans
7924d51665 PyBullet: deal with backward compatibility of b3RaycastBatchAddRay:
use b3RaycastBatchAddRays API to enable MAX_RAY_INTERSECTION_BATCH_SIZE_STREAMING num rays.
Old API (b3RaycastBatchAddRay) sticks to 256 rays, MAX_RAY_INTERSECTION_BATCH_SIZE.
2018-06-16 12:28:21 -07:00
erwincoumans
04d03d10be Fix memory leak due to batchRayCast never deleting the btTaskScheduler.
(and issue with TaskScheduler/btTaskScheduler.cpp, add JobQueue::exit, call it first, since it uses the m_threadSupport which was deleted before the destrucor was called.
Use a hashmap to store user timers, to avoid allocating many identical strings.
2018-06-16 09:37:53 -07:00
erwincoumans
23f9250e04 Merge remote-tracking branch 'bp/master' 2018-06-16 06:58:10 -07:00
erwincoumans
d660042d76
Merge pull request #1763 from YunfeiBai/master
Add the pdControlPlugin to the joint control C API, and add the PD co…
2018-06-16 06:57:50 -07:00
erwincoumans
f517b03534 Expose pushProfileTimer / pop ProfileTimer in PhysicsClient API to benchmark Python parts of PyBullet.
reduce 'm_cooldownTime' from 1000 microseconds to 100 microseconds (overhead in raycast is too large)
If needed, we can expose this cooldown time.
Replace malloc by btAlignedObjectArray (going through Bullet's memory allocator)
2018-06-16 06:19:49 -07:00
erwincoumans
bb8cbcdaae Merge remote-tracking branch 'bp/master' 2018-06-16 06:06:18 -07:00
Erwin Coumans
fbbd675ed6 expose PyBullet API to wakeup/put objects to sleep, enable/disable deactivation
fix wakeup -> reset deactivation clock
2018-06-15 21:26:26 -07:00
YunfeiBai
1c0de3c4cb Add the pdControlPlugin to the joint control C API, and add the PD control mode (also available in pybullet). Modify the pdControl pybullet example to use the PD control mode with setJointMotorControl API. 2018-06-15 17:59:26 -07:00
Tigran Gasparian
d244cf6061 Changes the default number of rays per thread from 32 to 16, when the user lets Bullet decide. 2018-06-15 17:13:10 +02:00
Tigran Gasparian
08409cae9f Adds multithreading support for batch ray casts.
To enable the feature, enable the BULLET2_MULTITHREADING option.

Increases the number of rays that can go in a batch request by storing
them in the shared memory stream instead of the shared memory command.
Adds the API b3RaycastBatchSetNumThreads to specify the number of
threads to use for the raycast batch, also adds the argument numThreads
to the pybullet function rayTestBatch.
Rays are distributed among the threads in a greedy fashion there's a shared
queue of work, once a thread finishes its task, it picks the next
available ray from the task. This works better than pre-distributing the
rays among threads, since there's a large variance in computation time per ray.

Some controversial changes:
- Added a pointer to PhysicsClient to the SharedMemoryCommand struct, this
was necessary to keep the C-API the same for b3RaycastBatchAddRay, while
adding the ray to the shared memory stream instead of the command
struct. I think this may be useful to simplify other APIs as well, that
take both a client handle and a command handle.
- Moved #define SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE to
SharedMemoryPublic. This was necessary for the definition of
MAX_RAY_INTERSECTION_BATCH_SIZE.
2018-06-15 16:47:04 +02:00
erwincoumans
4d6741f5cd PyBullet: expose STATE_LOGGING_ALL_COMMANDS and STATE_REPLAY_ALL_COMMANDS
See examples/pybullet/examples/commandLogAndPlayback.py for an example.
2018-06-12 16:56:45 -07:00
erwincoumans
97c6937388 Simplify GJK. Still needs double precision for large differences of feature scales.
Extract faces directly from btConvexHullComputer (in initializePolyhedralFeatures), instead of reconstructing them, thanks to Josh Klint in #1654
PyBullet: use initializePolyhedralFeatures for convex hulls and boxes (to allow SAT)
PyBullet: expose setPhysicsEngineParameter(enableSAT=0 or 1) to enable Separating Axis Test based collision detection for convex vs convex/box and convex versus concave triangles (in a triangle mesh).
2018-06-12 16:08:46 -07:00
erwincoumans
3eebcd40ca exposed a few more methods in the C++ b3RobotSimulatorClientAPI (_NoDirect base class) 2018-06-09 19:40:12 -07:00
Erwin Coumans
ad35beb61f fix typo 2018-06-05 16:25:43 -07:00
erwincoumans
b6f5cb4c34 enable pdControlPlugin by default (requires pdControlPlugin.cpp and b3RobotSimulatorClientAPI_NoDirect.cpp)
add pdControl.py example, make pdControlPlugin functional
reduce memory usage
fix examples/pybullet/gym/pybullet_data/random_urdfs/948/948.urdf, fixes issue #1704
2018-06-05 15:59:01 -07:00
Erwin Coumans
7bd84740d7 PyBullet / BulletRobotics: prepare for pdControlPlugin and collisionFilterPlugin
Split examples/SharedMemory/b3RobotSimulatorClientAPI_NoGUI.* and move to examples/SharedMemory/b3RobotSimulatorClientAPI_NoGUI.cpp and examples/SharedMemory/b3RobotSimulatorClientAPI_NoDirect.cpp
2018-06-05 11:41:41 +10:00
erwincoumans
b6120e760a PyBullet.addUserData / getUserData / removeUserData / getUserDataId / getNumUserData / getUserDataInfo
See examples/pybullet/examples/userData.py how to use it. TODO: add to PyBullet Quickstart Guide.
Thanks to Tigran Gasparian for the contribution!
2018-06-02 13:40:08 -07:00
erwincoumans
cb6b7a7c38 PyBullet: expose flags to createMultiBody 2018-06-02 11:37:14 -07:00
erwincoumans
68ea22bfd0 undo git merge conflict mess-up with IK 2018-06-01 22:50:06 -07:00
erwincoumans
2d40a18315 picking shouldn't activate (wakeup) sleeping objects 2018-06-01 09:34:18 -07:00
erwincoumans
1dec33d44b move default linearslop to 0 2018-05-30 12:31:29 -07:00
Erwin Coumans
8ace9251aa pass by pointer instead of reference to satisy compiler 2018-05-23 14:22:22 +10:00
Erwin Coumans
77c332bd88 PyBullet: add option to cache graphics shapes for URDF files, handy for benchmarks with many duplicate robots
See https://github.com/erwincoumans/pybullet_robots ANYmal.py for an example.
PyBullet: Expose p.setPhysicsEngineParameter(solverResidualThreshold=1e-2) (b3PhysicsParamSetSolverResidualThreshold), increases solver performance a lot
PyBullet: Expose p.setPhysicsEngineParameter(contactSlop) Set it to zero, to avoid issues with restitution.
PyBullet: Expose isNumpyEnabled, return True is PyBullet was compiled with NUMPY support for 'getCameraImage'.
PyBullet: Expose p.ChangeDynamics(objectUid, linkIndex, contactProcessingThreshold), to avoid issues of speculative/predictive contacts with restitution.
See also http://twvideo01.ubm-us.net/o1/vault/gdc2012/slides/Programming%20Track/Vincent_ROBERT_Track_ADifferentApproach.pdf
2018-05-23 13:26:00 +10:00
Yuchen Wu
f03ae5a857 Expose CFM parameters in PhysicsClient.
Add b3PhysicsParamSetDefaultGlobalCFM() and
b3PhysicsParamSetDefaultFrictionCFM().
2018-05-16 13:46:19 -07:00
erwincoumans
e5a9b42f9a expose PyBullet.setPhysicsEngineParameter(jointFeedbackMode)
use p.JOINT_FEEDBACK_IN_JOINT_FRAME if you want the joint feedback expressed in joint frame (instead of link inertial frame)
use p.JOINT_FEEDBACK_IN_WORLD_SPACE if you want the joint feedback in world space coordinates, instead of local link/joint coordinates.
Example: p.setPhysicsEngineParameter(jointFeedbackMode=p.JOINT_FEEDBACK_IN_WORLD_SPACE+p.JOINT_FEEDBACK_IN_JOINT_FRAME)
2018-05-11 19:52:06 -07:00
Erwin Coumans
414b3ef9bb PyBullet urdfEditor improvements: saveUrdf mesh scale, fix incorrect index, add getCameraImage in examples/combineUrdf.py 2018-05-09 10:28:12 -07:00
Erwin Coumans
84b20bda80 don't use the URDF inertia element, unless flag CUF_USE_URDF_INERTIA is set, not for the diagonal and also not for the inertial frame shift. 2018-05-03 14:24:16 -07:00
Erwin Coumans
4a8ad1a54e fix posix memory release issues
fix compile problems on Mac OSX
reduce shared memory size on Mac (>512*1024 fails to allocate)
2018-05-02 15:39:16 -07:00
Jan Matas
b1f85268f0 Check for null 2018-04-30 19:01:53 +01:00
Jan Matas
21418934e0 Reset sparsesdf to free memory. 2018-04-25 16:17:28 +01:00
erwincoumans
391b0e4061
Merge pull request #1588 from GaborPuhr/Fix-#1582
Fix for #1582
2018-04-12 13:32:51 -07:00
Erwin Coumans
11008d8110 fixes, backwards compatibility 2018-04-12 09:28:30 -07:00
Erwin Coumans
0832d3fd22 disable velocity clamp (maxVelocity) in velocity control mode,
remove some warnings
2018-04-10 17:21:14 -07:00
erwincoumans
ec68290497 PyBullet createVisualShape/createVisualShapeArray: postpone visual shape conversion until we know the link inertial transform 2018-03-28 19:08:18 -07:00
yunfeibai
6b97e1e604 Expose API to set projective texture instead of using global. 2018-03-20 21:28:47 -07:00
yunfeibai
37696dd87e Add Bullet C API and pybullet API to set projective texture matrices. 2018-03-18 18:45:54 -07:00
yunfeibai
fd7aa8d0e1 Expose using projective texture as a flag in pybullet getCameraImage API. 2018-03-18 17:01:23 -07:00
jietan
f4ca3f5963 Fix a bug that createVisualShape(Array) does not have the correct color. Add urdfEditor.py to pybullet_utils. Remove all unnecessary changes of white spaces. 2018-03-14 21:14:44 -07:00
jietan
d91a58e050 Merge remote-tracking branch 'bp/master' into pullRequest 2018-03-14 20:19:31 -07:00
jietan
413be3547b fix a bug that createVisualShape(Array) does not have the correct color. Add urdfEditor.py to pybullet_utils. 2018-03-12 21:06:19 -07:00
erwincoumans
b62501d04d fix loadTexture for tinyrenderer 2018-03-12 19:40:13 -07:00
Erwin Coumans
69d343386d PyBullet/C-API: implement createVisualShapeArray, with multiple visual shapes (require 1 texture max, since visual shapes are merged) 2018-03-09 18:02:06 -08:00
Erwin Coumans
b578361acf Use kF_UseGjkConvexCastRaytest by default for raycast in PyBullet (it is more robust/accurate, but a bit slower)
Use 10*EPSILON, as suggested in Gino's paper:
http://www.continuousphysics.com/ftp/pub/test/files/physics/papers/jgt04raycast.pdf
2018-03-07 14:51:51 -08:00
a
2348c6ba0a Fix for #1582 2018-03-05 23:05:22 +01:00
erwincoumans
73a4334e30 explicitly remove textures during resetSimulation
move glViewport to Win32Window
2018-02-21 23:22:16 -08:00
Erwin Coumans
b0984de046 preparation to replace glew by glad 2018-02-20 19:44:02 -08:00
erwincoumans
01f58f8f02 PyBullet: soft bodies are rendered, so we don't need to also render wireframes in regular mode.
Use glBufferSubData instead of glMapBuffer/glUnmapBuffer, much faster soft body vertex sync.
Don't use a separate btSoftBodyWorldInfo, use the existing one in btSoftMultiBodyDynamicsWorld.
2018-02-18 11:09:42 -08:00
erwincoumans
a6849de99c
Merge pull request #1555 from JanMatas/softBody-opengl-rendering
Implemented support for softbodies in OpenGL renderer
2018-02-18 10:48:46 -08:00
erwincoumans
ddf304ca78 PyBullet: expose internal edge utility, to adjust edge normals to prevent object penetrating along triangle edges of concave triangle meshes
(due to local convex-triangle collisions causing opposite contact normals, use the pre-computed edge normal)
PyBullet: expose experimental continuous collision detection for maximal coordinate rigid bodies, to prevent tunneling.
2018-02-16 19:44:33 -08:00
Jan Matas
817fb40fb5 Revert "Create a new pointer in btCollisionShape instead of just using userPtr."
This reverts commit d2d987a5ed.

After discussion, we decided to use userPtr.
2018-02-12 11:26:39 +00:00
Jan Matas
d2d987a5ed Create a new pointer in btCollisionShape instead of just using userPtr. 2018-02-08 13:49:36 +00:00
Jan Matas
82214eb99f Implemented support for softbodies in OpenGL renderer 2018-02-08 13:31:40 +00:00
erwincoumans
a92423b6f7 minor clarification in UrdfRenderingInterface 2018-01-21 11:15:35 -08:00
erwincoumans
329a1f5a74 PyBullet: move TinyRenderer into a plugin, default statically loaded. You can also dynamically load a render plugin, as shown in renderPlugin.py example. premake has a way to compile the tinyRendererPlugin. 2018-01-17 12:48:48 -08:00
erwincoumans
df89ce6f92 small refactor of LinkVisualShapesConverter / TinyRendererVisualShapeConverter, it allows to use it in a Python module and in a PyBullet plugin. 2018-01-16 17:58:19 -08:00
Erwin Coumans
af43e6465d fix wrong enum type 2018-01-15 15:13:11 -08:00