Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
a74aa8e
Remove deprecated qp solvers
EtienneAr Jul 23, 2025
3be8eb2
Copy paste TSID implementation from go2_mpc-experiments
EtienneAr Jul 24, 2025
f1f7395
Move ID setting in nested class
EtienneAr Jul 24, 2025
aced2a6
Remove un-necessary members of ID
EtienneAr Jul 24, 2025
99248f9
Minor change to remove hardcoded base name from go2
EtienneAr Jul 24, 2025
7d2c35a
WiP: write ID test
EtienneAr Jul 24, 2025
7da7d87
Test ID posture task
EtienneAr Jul 24, 2025
1822f56
Enable base task
EtienneAr Jul 24, 2025
71c6cbf
WiP: properly add foot contacts in tsid
EtienneAr Jul 24, 2025
2d8dfd3
Add contacts and base costs
EtienneAr Jul 24, 2025
8ab667a
Properly compute dry run data in ID
EtienneAr Jul 24, 2025
b96ddeb
Contact now equality constraint and not cost
EtienneAr Jul 24, 2025
50ff095
Contact position computed with measured data, not target
EtienneAr Jul 24, 2025
99808ba
Add tsid to package xml
EtienneAr Jul 24, 2025
2072499
Minor test changes
EtienneAr Jul 24, 2025
7836cca
Do not add tasks if weight is LE than 0.
EtienneAr Jul 24, 2025
4ce49aa
Write ID contact test
EtienneAr Jul 24, 2025
2ee11a9
Make contact task cost not constraint
EtienneAr Jul 24, 2025
23fa376
Roughly tune contact weight in test
EtienneAr Jul 24, 2025
81037cb
Port contact tunning in default settings
EtienneAr Jul 24, 2025
7a3cc32
Skip first point in all tasks test
EtienneAr Jul 24, 2025
cd8cd5e
FIX QUATERNION CONVENTION for target state
EtienneAr Jul 25, 2025
70c7633
Make propper q_start for ID tests
EtienneAr Jul 25, 2025
57df367
Adjust default ID tuning and adjust tests
EtienneAr Jul 25, 2025
397d10d
Fix test all tasks
EtienneAr Jul 25, 2025
f5d9bdd
Remove default values for ID gain and weights
EtienneAr Jul 25, 2025
e409e99
Add baseTask test
EtienneAr Jul 25, 2025
8a73a0d
Add Pos Vel joint bounds
EtienneAr Jul 25, 2025
b221d1f
Add actuation limit task
EtienneAr Jul 25, 2025
535ce08
Add test on ID limits
EtienneAr Jul 28, 2025
14b6f9a
Test solver convergence with assert
EtienneAr Jul 28, 2025
4d1f730
Minor change on velocity limits check
EtienneAr Jul 28, 2025
68dc872
Fix joint limit test on tau
EtienneAr Jul 28, 2025
33a1cdd
Remove pose_base_ member
EtienneAr Jul 28, 2025
6832a1b
Propper use of tail and head for static size slices
EtienneAr Jul 28, 2025
1e7d294
Use data handler to compute base pose
EtienneAr Jul 28, 2025
38cd655
Use Eigen::Ref
EtienneAr Jul 29, 2025
a5b88cc
Split hpp and cpp thanks to eigen::ref
EtienneAr Jul 29, 2025
d737d79
Better type for f_target: using matrix N, 3 instead of flattened vect…
EtienneAr Jul 29, 2025
a86969c
ContactForce as matrix propagated in the mpc
EtienneAr Jul 30, 2025
01b63f7
Bind getBaseFrameName in robot handler
EtienneAr Jul 30, 2025
c4448db
Bind retro-compatible version of updateInternalData in datahandler
EtienneAr Jul 30, 2025
73dc091
Remove expose IDSolver that was deleted
EtienneAr Jul 30, 2025
f915d5d
Bind get[Ref]FootPose[ByName]
EtienneAr Jul 30, 2025
2349903
Fix test getContactForces
EtienneAr Jul 30, 2025
bdb0f98
Expose inverse dynamics in bindings
EtienneAr Jul 30, 2025
8354e63
Bind KinodynamicsIDSettings member var
EtienneAr Jul 30, 2025
030b339
Bind getAccelerations
EtienneAr Jul 30, 2025
4489a10
Remove qp from python examples
edantec Jul 30, 2025
f9e7997
Use kinoID class is go2_kino example
EtienneAr Jul 30, 2025
425472b
Update kinodynamics examples
EtienneAr Jul 30, 2025
b3e583a
Add 6D foot in model handler
EtienneAr Jul 31, 2025
5d1ce4a
Rename 6D foot into Quad
EtienneAr Aug 4, 2025
d6ebfb9
TargetContactForce now a list of vector instead of matrices
EtienneAr Aug 4, 2025
1093b70
Add QuadFoot test on talos
EtienneAr Aug 4, 2025
d933260
Contact motion task can be set as equality from user
EtienneAr Aug 11, 2025
793adba
Fix 6D foot contact point error
EtienneAr Aug 11, 2025
2008767
Add tsid in pixi dependencies
EtienneAr Aug 12, 2025
ab1494e
Add tsid to readme
EtienneAr Aug 12, 2025
3827939
Update lockfile
EtienneAr Aug 12, 2025
afd614d
FIX PACKAGE.XML FOR COLCON git add -p!
EtienneAr Aug 12, 2025
962a2ad
Factorize tests
EtienneAr Aug 13, 2025
0418e68
Minor change
EtienneAr Aug 13, 2025
667dcc8
Fix test class
EtienneAr Aug 13, 2025
cbe8c03
Reduce posture task test length
EtienneAr Aug 13, 2025
f1b5346
Convert all test to new 'framework'
EtienneAr Aug 13, 2025
ea1b7f1
DataHandler fk using vel
EtienneAr Aug 13, 2025
89b411d
6DFoot to QuadFoot
EtienneAr Aug 13, 2025
145732f
Mega clean : RobotHandlers only deals with foot nb, names only used t…
EtienneAr Aug 13, 2025
ac5918e
Properly test contacts
EtienneAr Aug 14, 2025
9d552e2
Remove print and useless code in tests
EtienneAr Aug 14, 2025
765065f
Minor fix in contact tests
EtienneAr Aug 14, 2025
422ec2e
Fix all tasks tests
EtienneAr Aug 14, 2025
123ae2b
Minor fix go2 kino excample : change of api
EtienneAr Aug 14, 2025
bb7b21c
Move ID to separate folder
EtienneAr Aug 14, 2025
ed9f7ed
Use getFoobNb instead of calling size on various array
EtienneAr Aug 18, 2025
9f01f91
Remove deprecated test
EtienneAr Aug 18, 2025
acd39ce
Add minor comments in KinoID
EtienneAr Aug 18, 2025
758c3b5
Add assert on contact forces size
EtienneAr Aug 19, 2025
8fae3cf
Find src reccursively
EtienneAr Aug 19, 2025
5b02757
Minor changes in kinodynamics
EtienneAr Aug 19, 2025
c7cc3b4
Stop tracking pycache
EtienneAr Aug 19, 2025
893aad4
Add centroidal ID class
EtienneAr Aug 19, 2025
93bd597
Bond centroidal ID
EtienneAr Aug 19, 2025
25b75f1
Update talos example
EtienneAr Aug 19, 2025
b234747
Forgot changes ?
EtienneAr Aug 19, 2025
806c1a9
Initialize feet_tracked vector of bool properly
EtienneAr Aug 20, 2025
7b27c34
Desembiguate binding proxy for kino and centroidal
EtienneAr Aug 20, 2025
e5527f8
Minor fix in centroidal example
EtienneAr Aug 20, 2025
98acfac
Fixes in centroidal
EtienneAr Aug 21, 2025
b201f2c
Default set target run in centroidal constructor
EtienneAr Aug 21, 2025
f8f8afc
Bind missing member of KinodynamicsID::Settings contact_motion_equality
EtienneAr Aug 21, 2025
b38fedb
Fix getAccelerations
EtienneAr Aug 22, 2025
30bd6fb
Set baseTask mask properly for centroidal
EtienneAr Sep 19, 2025
912f3f0
Minor cleaning
EtienneAr Sep 19, 2025
746d709
Minor update of default ID parameters
EtienneAr Sep 19, 2025
6aab3e1
Add ID test in cmakelists
EtienneAr Sep 19, 2025
662fb8b
Minor tuning in talos kino example
EtienneAr Sep 22, 2025
c27cacf
Homogenize centroidal and kino talos examples
EtienneAr Sep 22, 2025
2059fab
Set of gains that works for STATIC centroidal
EtienneAr Sep 22, 2025
092858d
Minor fix in talos centroidal example but overall still not working
EtienneAr Sep 22, 2025
d4aec23
copy paste kino test to centroidal
EtienneAr Sep 23, 2025
5d3d789
remove easy initilization of ID Settings and make centroidal test com…
EtienneAr Sep 23, 2025
e161e2b
Make centroidal contact point tests pass by adding small com cost (to…
EtienneAr Sep 23, 2025
489f4fb
Make centroidal baseTask test pass by adding small com task (to compe…
EtienneAr Sep 23, 2025
e364e33
Improve base orientation task test in centroidalID
EtienneAr Sep 24, 2025
9b72b70
remove useless task in centroidal baseTask test
EtienneAr Sep 24, 2025
756e40e
Add test on centroidalID com task
EtienneAr Sep 24, 2025
3a04d4d
Add centroidal foot tracking test
EtienneAr Sep 26, 2025
66b9301
Make setReferenceFootPlacement use foot index instead of name for coh…
EtienneAr Sep 27, 2025
d277faf
Fix benchmark compilation
EtienneAr Sep 27, 2025
5677470
Rename parent frame ref for foot placement
EtienneAr Sep 27, 2025
354c585
Fix default reference foot frame placement
EtienneAr Sep 27, 2025
2e488fb
No need to set foot ref placement in examples & test, default one suf…
EtienneAr Sep 27, 2025
05d0689
Use getFeetNb instead of doing len() by hand
EtienneAr Sep 29, 2025
0982a50
Compatility with pinocchio 3
EtienneAr Sep 29, 2025
4ba2990
Update tsid to have fix and proxqp flag by default
EtienneAr Sep 30, 2025
1eb20ff
Use tsid latest build to actually have proxqp
EtienneAr Sep 30, 2025
d44dd93
Add TSID in conda deps
EtienneAr Oct 9, 2025
c1e0a38
Use interpolateState in examples when relevant
EtienneAr Oct 9, 2025
6581e2f
Remove comments
EtienneAr Oct 9, 2025
3a1cbda
Remove commented code on TargetContactForce
EtienneAr Oct 9, 2025
fc424cc
Minor typo
EtienneAr Oct 9, 2025
0dd62ea
Resize samples instead of reallocating
EtienneAr Oct 13, 2025
2d18953
Remove pointer to solver and directly have object in class
EtienneAr Oct 13, 2025
6d2edb3
Make tsid task unique_pointer
EtienneAr Oct 13, 2025
d4d10e9
Rename id files
EtienneAr Oct 13, 2025
d879f1d
Ignore .vscode
EtienneAr Oct 13, 2025
4694bcc
Minor comments
EtienneAr Oct 13, 2025
8b7ec62
minor fix on renaming id headers
EtienneAr Oct 13, 2025
b7d18a1
Minor fix of sign ismatch warnings
EtienneAr Oct 13, 2025
e18daee
Fix some more signs & unused variables warnings
EtienneAr Oct 13, 2025
9a45f4d
Add static cast to remove one warning
EtienneAr Oct 14, 2025
555965a
Fix the last remaining warnings introduced in this PR
EtienneAr Oct 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,9 @@

.cache/
build*/
/__pycache__/
__pycache__/


.vscode
CMakeFiles/
CMakeCache.txt
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ endif()
include(dependencies.cmake)

# Main Library
file(GLOB mpc_SOURCE CONFIGURE_DEPENDS src/*.cpp)
file(GLOB mpc_HEADER CONFIGURE_DEPENDS include/${PROJECT_NAME}/*.hpp)
file(GLOB_RECURSE mpc_SOURCE CONFIGURE_DEPENDS src/*.cpp)
file(GLOB_RECURSE mpc_HEADER CONFIGURE_DEPENDS include/${PROJECT_NAME}/*.hpp)

add_library(${PROJECT_NAME} SHARED ${mpc_HEADER} ${mpc_SOURCE})
target_include_directories(
Expand All @@ -112,6 +112,7 @@ target_link_libraries(
aligator::aligator
example-robot-data::example-robot-data
ndcurves::ndcurves
tsid::tsid
)
target_link_libraries(${PROJECT_NAME} PUBLIC OpenMP::OpenMP_CXX)
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${mpc_HEADER}")
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,6 @@ source install/setup.bash
* [Aligator](https://github.com/edantec/aligator) temporary_fix branch
* [example-robot-data](https://github.com/Gepetto/example-robot-data)
* [ndcurves](https://github.com/loco-3d/ndcurves)
* [tsid](https://github.com/stack-of-tasks/tsid)
* (optional) [eigenpy](https://github.com/stack-of-tasks/eigenpy)>=3.9.0 (Python bindings)
* (optional) [bullet](https://github.com/bulletphysics/bullet3) (Simulation examples)
17 changes: 8 additions & 9 deletions benchmark/go2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ int main()
ref_FR_foot.translation() = Eigen::Vector3d(0.17, -0.15, 0.0);
ref_RL_foot.translation() = Eigen::Vector3d(-0.24, 0.15, 0.0);
ref_RR_foot.translation() = Eigen::Vector3d(-0.24, -0.15, 0.0);
model_handler.addFoot("FL_foot", base_joint_name);
model_handler.addFoot("FR_foot", base_joint_name);
model_handler.addFoot("RL_foot", base_joint_name);
model_handler.addFoot("RR_foot", base_joint_name);
model_handler.setFootReferencePlacement("FL_foot", ref_FL_foot);
model_handler.setFootReferencePlacement("FR_foot", ref_FR_foot);
model_handler.setFootReferencePlacement("RL_foot", ref_RL_foot);
model_handler.setFootReferencePlacement("RR_foot", ref_RR_foot);
model_handler.addPointFoot("FL_foot", base_joint_name);
model_handler.addPointFoot("FR_foot", base_joint_name);
model_handler.addPointFoot("RL_foot", base_joint_name);
model_handler.addPointFoot("RR_foot", base_joint_name);
model_handler.setFootReferencePlacement(model_handler.getFootNb("FL_foot"), ref_FL_foot);
model_handler.setFootReferencePlacement(model_handler.getFootNb("FR_foot"), ref_FR_foot);
model_handler.setFootReferencePlacement(model_handler.getFootNb("RL_foot"), ref_RL_foot);
model_handler.setFootReferencePlacement(model_handler.getFootNb("RR_foot"), ref_RR_foot);

RobotDataHandler data_handler(model_handler);

Expand Down Expand Up @@ -109,7 +109,6 @@ int main()
int T_fly = 30;
int T_contact = 5;
simple_mpc::MPCSettings mpc_settings;
mpc_settings.ddpIteration = 1;
mpc_settings.support_force = -gravity[2] * model_handler.getMass();
mpc_settings.TOL = 1e-4;
mpc_settings.mu_init = 1e-8;
Expand Down
31 changes: 17 additions & 14 deletions benchmark/talos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,16 @@ int main()
RobotModelHandler model_handler(model, "half_sitting", base_joint);

// Add feet
model_handler.addFoot("left_sole_link", base_joint);
model_handler.addFoot("right_sole_link", base_joint);
Eigen::Matrix<double, 4, 3> foot_quad{{0.1, 0.075, 0}, {-0.1, 0.075, 0}, {-0.1, -0.075, 0}, {0.1, -0.075, 0}};
model_handler.addQuadFoot("left_sole_link", base_joint, foot_quad);
model_handler.addQuadFoot("right_sole_link", base_joint, foot_quad);

model_handler.setFootReferencePlacement(
"left_sole_link", pinocchio::SE3(Eigen::Quaternion(0., 0., 0., 1.), Eigen::Vector3d(0., 0.1, 0.)));
model_handler.getFootNb("left_sole_link"),
pinocchio::SE3(Eigen::Quaternion(0., 0., 0., 1.), Eigen::Vector3d(0., 0.1, 0.)));
model_handler.setFootReferencePlacement(
"right_sole_link", pinocchio::SE3(Eigen::Quaternion(0., 0., 0., 1.), Eigen::Vector3d(0., -0.1, 0.)));
model_handler.getFootNb("right_sole_link"),
pinocchio::SE3(Eigen::Quaternion(0., 0., 0., 1.), Eigen::Vector3d(0., -0.1, 0.)));

RobotDataHandler data_handler(model_handler);

Expand Down Expand Up @@ -152,36 +155,36 @@ int main()
for (std::size_t i = 0; i < 10; i++)
{
std::map<std::string, bool> contact_state;
contact_state.insert({model_handler.getFootName(0), true});
contact_state.insert({model_handler.getFootName(1), true});
contact_state.insert({model_handler.getFootFrameName(0), true});
contact_state.insert({model_handler.getFootFrameName(1), true});
contact_states.push_back(contact_state);
}
for (std::size_t i = 0; i < 50; i++)
{
std::map<std::string, bool> contact_state;
contact_state.insert({model_handler.getFootName(0), true});
contact_state.insert({model_handler.getFootName(1), false});
contact_state.insert({model_handler.getFootFrameName(0), true});
contact_state.insert({model_handler.getFootFrameName(1), false});
contact_states.push_back(contact_state);
}
for (std::size_t i = 0; i < 10; i++)
{
std::map<std::string, bool> contact_state;
contact_state.insert({model_handler.getFootName(0), true});
contact_state.insert({model_handler.getFootName(1), true});
contact_state.insert({model_handler.getFootFrameName(0), true});
contact_state.insert({model_handler.getFootFrameName(1), true});
contact_states.push_back(contact_state);
}
for (std::size_t i = 0; i < 50; i++)
{
std::map<std::string, bool> contact_state;
contact_state.insert({model_handler.getFootName(0), false});
contact_state.insert({model_handler.getFootName(1), true});
contact_state.insert({model_handler.getFootFrameName(0), false});
contact_state.insert({model_handler.getFootFrameName(1), true});
contact_states.push_back(contact_state);
}
for (std::size_t i = 0; i < 10; i++)
{
std::map<std::string, bool> contact_state;
contact_state.insert({model_handler.getFootName(0), true});
contact_state.insert({model_handler.getFootName(1), true});
contact_state.insert({model_handler.getFootFrameName(0), true});
contact_state.insert({model_handler.getFootFrameName(1), true});
contact_states.push_back(contact_state);
}

Expand Down
2 changes: 1 addition & 1 deletion bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ set(
expose-robot-handler.cpp
expose-problem.cpp
expose-mpc.cpp
expose-qp.cpp
expose-interpolate.cpp
expose-centroidal.cpp
expose-fulldynamics.cpp
expose-kinodynamics.cpp
expose-inverse-dynamics.cpp
expose-friction-compensation.cpp
)

Expand Down
97 changes: 97 additions & 0 deletions bindings/expose-inverse-dynamics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include <eigenpy/eigenpy.hpp>

#include "simple-mpc/inverse-dynamics/centroidal-id.hpp"
#include "simple-mpc/inverse-dynamics/kinodynamics-id.hpp"

namespace simple_mpc
{
namespace python
{
namespace bp = boost::python;

Eigen::VectorXd solveKinoProxy(
KinodynamicsID & self,
const double t,
const Eigen::Ref<const Eigen::VectorXd> & q_meas,
const Eigen::Ref<const Eigen::VectorXd> & v_meas)
{
Eigen::VectorXd tau_res(self.model_handler_.getModel().nv - 6);
self.solve(t, q_meas, v_meas, tau_res);
return tau_res;
}

Eigen::VectorXd getAccelerationsKinoProxy(KinodynamicsID & self)
{
Eigen::VectorXd a(self.model_handler_.getModel().nv);
self.getAccelerations(a);
return a;
}

Eigen::VectorXd solveCentroidalProxy(
CentroidalID & self,
const double t,
const Eigen::Ref<const Eigen::VectorXd> & q_meas,
const Eigen::Ref<const Eigen::VectorXd> & v_meas)
{
Eigen::VectorXd tau_res(self.model_handler_.getModel().nv - 6);
self.solve(t, q_meas, v_meas, tau_res);
return tau_res;
}

Eigen::VectorXd getAccelerationsCentroidalProxy(CentroidalID & self)
{
Eigen::VectorXd a(self.model_handler_.getModel().nv);
self.getAccelerations(a);
return a;
}

void setTarget_CentroidalID(
CentroidalID & self,
const Eigen::Ref<const Eigen::Vector<double, 3>> & com_position,
const Eigen::Ref<const Eigen::Vector<double, 3>> & com_velocity,
const CentroidalID::FeetPoseVector & feet_pose,
const CentroidalID::FeetVelocityVector & feet_velocity,
const std::vector<bool> & contact_state_target,
const std::vector<CentroidalID::TargetContactForce> & f_target)
{
self.setTarget(com_position, com_velocity, feet_pose, feet_velocity, contact_state_target, f_target);
}

void exposeInverseDynamics()
{
bp::class_<KinodynamicsID::Settings>("KinodynamicsIDSettings", bp::init<>(bp::args("self")))
.def_readwrite("friction_coefficient", &KinodynamicsID::Settings::friction_coefficient)
.def_readwrite("contact_weight_ratio_max", &KinodynamicsID::Settings::contact_weight_ratio_max)
.def_readwrite("contact_weight_ratio_min", &KinodynamicsID::Settings::contact_weight_ratio_min)
.def_readwrite("kp_base", &KinodynamicsID::Settings::kp_base)
.def_readwrite("kp_posture", &KinodynamicsID::Settings::kp_posture)
.def_readwrite("kp_contact", &KinodynamicsID::Settings::kp_contact)
.def_readwrite("w_base", &KinodynamicsID::Settings::w_base)
.def_readwrite("w_posture", &KinodynamicsID::Settings::w_posture)
.def_readwrite("w_contact_motion", &KinodynamicsID::Settings::w_contact_motion)
.def_readwrite("w_contact_force", &KinodynamicsID::Settings::w_contact_force)
.def_readwrite("contact_motion_equality", &KinodynamicsID::Settings::contact_motion_equality);

bp::class_<KinodynamicsID, boost::noncopyable>(
"KinodynamicsID", bp::init<const simple_mpc::RobotModelHandler &, double, const KinodynamicsID::Settings>(
bp::args("self", "model_handler", "control_dt", "settings")))
.def("setTarget", &KinodynamicsID::setTarget)
.def("solve", &solveKinoProxy)
.def("getAccelerations", &getAccelerationsKinoProxy);

bp::class_<CentroidalID::Settings, bp::bases<KinodynamicsID::Settings>>(
"CentroidalIDSettings", bp::init<>(bp::args("self")))
.def_readwrite("kp_com", &CentroidalID::Settings::kp_com)
.def_readwrite("kp_feet_tracking", &CentroidalID::Settings::kp_feet_tracking)
.def_readwrite("w_com", &CentroidalID::Settings::w_com)
.def_readwrite("w_feet_tracking", &CentroidalID::Settings::w_feet_tracking);

bp::class_<CentroidalID, boost::noncopyable>(
"CentroidalID", bp::init<const simple_mpc::RobotModelHandler &, double, const CentroidalID::Settings>(
bp::args("self", "model_handler", "control_dt", "settings")))
.def("setTarget", &setTarget_CentroidalID)
.def("solve", &solveCentroidalProxy)
.def("getAccelerations", &getAccelerationsCentroidalProxy);
}
} // namespace python
} // namespace simple_mpc
127 changes: 0 additions & 127 deletions bindings/expose-qp.cpp

This file was deleted.

Loading
Loading