diff --git a/CMakeLists.txt b/CMakeLists.txt
index f7942870da7ecf50291e955e4aba9d23b02597e1..9767a413e82b6dff4ba2d4ec64e18f18e94ed81c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -359,3 +359,14 @@ target_link_libraries(demo_TPGMMProduct01
 		${GLFW_LIB}
 		${ARMADILLO_LIBRARIES}
 		)
+
+add_executable(demo_TPGMR01
+		${GFX2_SUPPORT_SOURCES}
+		${PROJECT_SOURCE_DIR}/src/demo_TPGMR01.cpp
+		)
+target_link_libraries(demo_TPGMR01
+		${OPENGL_LIBRARIES}
+		${GLEW_LIBRARIES}
+		${GLFW_LIB}
+		${ARMADILLO_LIBRARIES}
+		)
\ No newline at end of file
diff --git a/data/data_tpgmr_frames.txt b/data/data_tpgmr_frames.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cfab7a6acd784b50924a512a9ba75b4448eb38ac
--- /dev/null
+++ b/data/data_tpgmr_frames.txt
@@ -0,0 +1,6 @@
+ARMA_MAT_TXT_FN008
+4 10
+   1.66483521461487e-01   2.16262057423592e-01   1.66483521461487e-01   6.82893320918083e-02   1.66483521461487e-01   8.84615406394005e-02   1.66483521461487e-01   2.68131881952286e-01   1.66483521461487e-01   1.46153852343559e-01
+   4.58745867013931e-01   1.20309405028820e-01   4.58745867013931e-01   8.72561037540436e-02   4.58745867013931e-01   2.02970296144485e-01   4.58745867013931e-01   2.15346530079842e-01   4.58745867013931e-01   1.33663371205330e-01
+   0.00000000000000e+00  -3.75198520487174e-04   0.00000000000000e+00  -2.24803457967937e-03   0.00000000000000e+00   1.85198104009032e-03   0.00000000000000e+00   2.19112867489457e-03   0.00000000000000e+00  -1.08944403473288e-03
+   2.47524753212929e-02  -9.23957489430904e-03   2.47524753212929e-02  -8.34755878895521e-03   2.47524753212929e-02  -1.21426973491907e-02   2.47524753212929e-02  -9.19921137392521e-03   2.47524753212929e-02  -1.49771561846137e-02
diff --git a/data/data_tpgmr_trajectories.txt b/data/data_tpgmr_trajectories.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cbf512a44c991ee2c2338b7aaee66b5351539526
--- /dev/null
+++ b/data/data_tpgmr_trajectories.txt
@@ -0,0 +1,12 @@
+ARMA_CUB_TXT_FN008
+2 200 5
+  -1.37362637362637e-03  -1.61936053895853e-03  -1.86509470429068e-03  -2.11082886962284e-03  -2.35656303495499e-03  -2.73206692804683e-03  -3.22353525871114e-03  -3.64321608040201e-03  -3.88895024573417e-03  -4.13468441106632e-03  -4.38041857639848e-03  -4.62615274173063e-03  -4.46877243359655e-03  -4.22303826826440e-03  -3.97730410293224e-03  -3.73156993760009e-03  -3.48583577226793e-03  -3.24010160693578e-03  -2.99436744160362e-03  -2.74863327627147e-03  -2.50289911093931e-03  -2.25716494560716e-03  -2.01143078027500e-03  -1.76569661494285e-03  -1.51996244961069e-03  -1.27422828427854e-03  -1.02849411894638e-03  -7.82759953614225e-04  -5.37025788282070e-04  -2.91291622949914e-04  -4.55574576177593e-05   2.00176707714397e-04   4.45910873046551e-04   6.91645038378706e-04   9.37379203710862e-04   1.18311336904302e-03   1.42884753437517e-03   1.67458169970733e-03   1.92031586503948e-03   2.16605003037164e-03   2.41178419570379e-03   2.65751836103595e-03   2.90325252636810e-03   3.14898669170026e-03   3.39472085703241e-03   3.64045502236457e-03   3.88618918769673e-03   4.13192335302888e-03   4.37765751836104e-03   4.62339168369319e-03   4.86912584902535e-03   5.11486001435750e-03   5.36059417968966e-03   5.60632834502181e-03   5.85206251035397e-03   6.09779667568612e-03   6.34353084101828e-03   6.58926500635043e-03   6.83499917168259e-03   7.29333480589762e-03   7.78480313656193e-03   8.12165221712960e-03   8.36738638246176e-03   8.61312054779391e-03   8.85885471312607e-03   9.10458887845822e-03   9.35032304379038e-03   9.59605720912254e-03   1.00681981335248e-02   1.05596664641891e-02   1.08827102545695e-02   1.11284444199017e-02   1.13741785852339e-02   1.16199127505660e-02   1.18656469158982e-02   1.21113810812303e-02   1.23571152465625e-02   1.26028494118946e-02   1.28485835772268e-02   1.34587774035010e-02   1.41959798994975e-02   1.46846871721244e-02   1.49304213374565e-02   1.52424208956872e-02   1.57338892263515e-02   1.62502070793528e-02   1.74788779060136e-02   1.87075487326744e-02   2.09163951626263e-02   2.33737368159479e-02   2.48647081561654e-02   2.56019106521619e-02   2.62590424650726e-02   2.67505107957369e-02   2.72419791264012e-02   2.77334474570655e-02   2.82249157877299e-02   2.89262245292396e-02   2.96634270252361e-02   3.02487713291733e-02   3.07402396598377e-02   3.11378320172290e-02   3.13835661825612e-02   3.17010878568668e-02   3.24382903528632e-02   3.31754928488597e-02   3.39126953448561e-02   3.46498978408526e-02   3.52214368546027e-02   3.57129051852670e-02   3.60966922524711e-02   3.63424264178033e-02   3.65881605831355e-02   3.68338947484676e-02   3.70796289137998e-02   3.73253630791319e-02   3.75710972444641e-02   3.78168314097962e-02   3.80625655751284e-02   3.84297862941079e-02   3.89212546247722e-02   3.94127229554365e-02   3.99041912861008e-02   4.03956596167651e-02   4.08871279474295e-02   4.13785962780938e-02   4.16767905461373e-02   4.19225247114694e-02   4.21682588768016e-02   4.24139930421337e-02   4.26597272074659e-02   4.29054613727981e-02   4.31511955381302e-02   4.33969297034624e-02   4.36426638687945e-02   4.40954773869347e-02   4.45869457175990e-02   4.52275111822851e-02   4.59647136782815e-02   4.65196863438069e-02   4.67654205091391e-02   4.70111546744713e-02   4.72568888398034e-02   4.75026230051356e-02   4.77483571704677e-02   4.79940913357999e-02   4.82398255011320e-02   4.84855596664642e-02   4.87312938317963e-02   4.89770279971285e-02   4.92227621624607e-02   4.94684963277928e-02   4.97142304931250e-02   4.99599646584571e-02   5.02056988237893e-02   5.06281407035176e-02   5.11196090341819e-02   5.14923518692363e-02   5.17380860345684e-02   5.19838201999006e-02   5.22295543652328e-02   5.24752885305649e-02   5.27210226958971e-02   5.29667568612292e-02   5.34030040311447e-02   5.38944723618090e-02   5.42534099066762e-02   5.44991440720084e-02   5.45957811033188e-02   5.43500469379866e-02   5.41043127726545e-02   5.38585786073223e-02   5.36128444419902e-02   5.37757468661991e-02   5.40214810315313e-02   5.42672151968634e-02   5.45129493621956e-02   5.47586835275277e-02   5.50044176928599e-02   5.52501518581921e-02   5.54958860235242e-02   5.57416201888564e-02   5.55511071842730e-02   5.53053730189409e-02   5.48994974874372e-02   5.44080291567729e-02   5.40187199734938e-02   5.37729858081617e-02   5.35272516428295e-02   5.32815174774974e-02   5.30357833121652e-02   5.27900491468331e-02   5.25443149815009e-02   5.22985808161687e-02   5.20528466508366e-02   5.18071124855045e-02   5.15613783201723e-02   5.13156441548401e-02   5.10699099895080e-02   5.08241758241758e-02
+  -1.93069306930693e-01  -1.82737117932899e-01  -1.72404928935105e-01  -1.65455992835464e-01  -1.59551884836725e-01  -1.55011857969717e-01  -1.51690797220426e-01  -1.47076139774782e-01  -1.39326998026436e-01  -1.31909547738693e-01  -1.30064513989087e-01  -1.28219480239481e-01  -1.14570376635654e-01  -9.83340796391197e-02  -9.13685589664494e-02  -9.09995522165282e-02  -9.01164237026718e-02  -8.82713899530657e-02  -8.65507405011858e-02  -8.58127270013433e-02  -8.50747135015009e-02  -8.46600991757467e-02  -8.42910924258255e-02  -8.39220856759043e-02  -8.35530789259831e-02  -8.31840721760618e-02  -8.28150654261406e-02  -8.23216743784931e-02  -8.12146541287295e-02  -8.01076338789658e-02  -7.86564837388261e-02  -7.71804567391413e-02  -7.59614906214240e-02  -7.48544703716603e-02  -7.35774582483374e-02  -7.21014312486525e-02  -7.08741728444201e-02  -7.05051660944989e-02  -7.01361593445777e-02  -6.97671525946565e-02  -6.93981458447352e-02  -6.84735558983034e-02  -6.73665356485397e-02  -6.66409605784699e-02  -6.62719538285487e-02  -6.56956399157504e-02  -6.45886196659867e-02  -6.35147685622834e-02  -6.31457618123621e-02  -6.27767550624409e-02  -6.24077483125197e-02  -6.20387415625985e-02  -6.14582815065426e-02  -6.07202680067002e-02  -5.99822545068577e-02  -5.92442410070153e-02  -5.85435427964907e-02  -5.81745360465695e-02  -5.78055292966483e-02  -5.74365225467270e-02  -5.70675157968058e-02  -5.64663250244623e-02  -5.57283115246198e-02  -5.51354130387913e-02  -5.47664062888701e-02  -5.43393535333433e-02  -5.36013400335008e-02  -5.28633265336584e-02  -5.24652967809344e-02  -5.20962900310131e-02  -5.17272832810919e-02  -5.13582765311707e-02  -5.09892697812495e-02  -5.06202630313283e-02  -5.02512562814070e-02  -4.98822495314858e-02  -4.95132427815646e-02  -4.91442360316434e-02  -4.87752292817221e-02  -4.84062225318009e-02  -4.80372157818797e-02  -4.76682090319585e-02  -4.72992022820372e-02  -4.69301955321160e-02  -4.65611887821948e-02  -4.61921820322736e-02  -4.58231752823524e-02  -4.54541685324311e-02  -4.50851617825099e-02  -4.47161550325887e-02  -4.41398411197904e-02  -4.34018276199479e-02  -4.27840522745742e-02  -4.24150455246530e-02  -4.20460387747317e-02  -4.16770320248105e-02  -4.13080252748893e-02  -4.09390185249681e-02  -4.05700117750469e-02  -4.02010050251256e-02  -3.98319982752044e-02  -3.94629915252832e-02  -3.90939847753620e-02  -3.87249780254407e-02  -3.83559712755195e-02  -3.79869645255983e-02  -3.76179577756771e-02  -3.72489510257558e-02  -3.68799442758346e-02  -3.65109375259134e-02  -3.61419307759922e-02  -3.57729240260709e-02  -3.54039172761497e-02  -3.50349105262285e-02  -3.46659037763073e-02  -3.42968970263861e-02  -3.39278902764648e-02  -3.35588835265436e-02  -3.31898767766224e-02  -3.28208700267012e-02  -3.24518632767799e-02  -3.18921339370118e-02  -3.07851136872481e-02  -2.96946780105146e-02  -2.93256712605934e-02  -2.89566645106722e-02  -2.85876577607509e-02  -2.82186510108297e-02  -2.76464832412890e-02  -2.69084697414465e-02  -2.62865482528152e-02  -2.59175415028940e-02  -2.55485347529728e-02  -2.51795280030516e-02  -2.48105212531303e-02  -2.44415145032091e-02  -2.40725077532879e-02  -2.34796092674594e-02  -2.27415957676170e-02  -2.21404049952734e-02  -2.17713982453522e-02  -2.14023914954309e-02  -2.10333847455097e-02  -2.06643779955885e-02  -2.02953712456673e-02  -1.99263644957461e-02  -1.95573577458248e-02  -1.91883509959036e-02  -1.85042373584092e-02  -1.73972171086456e-02  -1.62901968588819e-02  -1.51831766091182e-02  -1.40761563593545e-02  -1.33215582864819e-02  -1.25835447866395e-02  -1.10494717813490e-02  -9.20443803174288e-03  -8.07254092243395e-03  -7.70353417251273e-03  -6.87845166426188e-03  -4.66441116473460e-03  -2.46280909497986e-03  -1.35578884521618e-03  -2.48768595452506e-04   2.00258719339273e-03   4.58563444284123e-03   6.17360731047978e-03   6.91162081032224e-03   1.02243892730982e-02   1.94495580211288e-02   2.88737416455211e-02   4.10509643929216e-02   5.32281871403220e-02   5.74282302602120e-02   6.00112775096605e-02   6.14955967958605e-02   6.22336102957029e-02   6.29716237955454e-02   6.37096372953878e-02   6.50405492810588e-02   7.05756505298772e-02   7.61107517786954e-02   8.32835796142428e-02   9.06637146126673e-02   9.37152760502181e-02   9.44532895500605e-02   9.54981176509611e-02   9.69741446506460e-02   9.83174950660895e-02   9.90555085659320e-02   9.97935220657744e-02   1.00531535565617e-01   1.01269549065459e-01   1.02268769590527e-01   1.03375789840291e-01   1.04134534056421e-01   1.04503540806342e-01   1.04959616564672e-01   1.05697630064514e-01   1.06435643564356e-01
+   2.74725274725275e-04   1.68286487381965e-03   2.31238610635596e-03   2.78176597272075e-03   3.25114583908554e-03   3.72052570545033e-03   4.18990557181512e-03   4.65928543817991e-03   5.12866530454470e-03   5.59804517090949e-03   6.06742503727428e-03   6.10055773372356e-03   5.63117786735877e-03   5.16179800099398e-03   4.69241813462919e-03   3.77574686619913e-03   3.20420785244906e-03   2.73482798608427e-03   2.26544811971948e-03   1.79606825335469e-03   1.32668838698989e-03   8.57308520625103e-04   3.87928654260312e-04  -8.14512121044780e-05  -5.50831078469270e-04  -1.21624606549230e-03  -2.03904136064940e-03  -2.50842122701419e-03  -2.97780109337898e-03  -3.44718095974377e-03  -3.91656082610856e-03  -4.38594069247336e-03  -4.85532055883815e-03  -5.32470042520294e-03  -5.79408029156773e-03  -6.26346015793252e-03  -7.14699872991330e-03  -7.75167044011265e-03  -8.22105030647744e-03  -8.69043017284223e-03  -9.25368601247999e-03  -1.01786404550224e-02  -1.06480203213872e-02  -1.11174001877519e-02  -1.15867800541167e-02  -1.22991330277762e-02  -1.30749903362969e-02  -1.35443702026617e-02  -1.40137500690265e-02  -1.44831299353912e-02  -1.49525098017560e-02  -1.54218896681208e-02  -1.58912695344856e-02  -1.63606494008504e-02  -1.68300292672152e-02  -1.72994091335800e-02  -1.82298856921973e-02  -1.87876194157601e-02  -1.92569992821249e-02  -1.97263791484897e-02  -2.01957590148545e-02  -2.06651388812193e-02  -2.11345187475841e-02  -2.16038986139489e-02  -2.20732784803137e-02  -2.31224805345408e-02  -2.41109393119443e-02  -2.45803191783091e-02  -2.50496990446739e-02  -2.55190789110387e-02  -2.64274670053565e-02  -2.70072891932188e-02  -2.74766690595836e-02  -2.79460489259484e-02  -2.84154287923132e-02  -2.88848086586780e-02  -2.93541885250428e-02  -3.02515323872108e-02  -3.08423988072229e-02  -3.13117786735877e-02  -3.17811585399525e-02  -3.22505384063173e-02  -3.27199182726821e-02  -3.31892981390469e-02  -3.36586780054117e-02  -3.41280578717765e-02  -3.45974377381413e-02  -3.50668176045060e-02  -3.55361974708708e-02  -3.60055773372356e-02  -3.64749572036004e-02  -3.69443370699652e-02  -3.74137169363300e-02  -3.78830968026948e-02  -3.83524766690596e-02  -3.88218565354244e-02  -3.92912364017892e-02  -3.97606162681540e-02  -4.02299961345187e-02  -4.06993760008835e-02  -4.11687558672483e-02  -4.16381357336131e-02  -4.21075155999779e-02  -4.25768954663427e-02  -4.30462753327075e-02  -4.35156551990723e-02  -4.39850350654371e-02  -4.44544149318019e-02  -4.49237947981667e-02  -4.54566789993926e-02  -4.63954387321222e-02  -4.68813849467116e-02  -4.80962504831852e-02  -4.89190457783423e-02  -4.93884256447071e-02  -4.98578055110719e-02  -5.03796454801480e-02  -5.13184052128776e-02  -5.18153956596168e-02  -5.22847755259816e-02  -5.27541553923463e-02  -5.32235352587111e-02  -5.36929151250759e-02  -5.41622949914407e-02  -5.46316748578055e-02  -5.51010547241703e-02  -5.55704345905351e-02  -5.63103981445690e-02  -5.70586448727152e-02  -5.75280247390800e-02  -5.79974046054448e-02  -5.84667844718096e-02  -5.93558451598653e-02  -5.99549947539897e-02  -6.04243746203545e-02  -6.08937544867193e-02  -6.14625324424320e-02  -6.23819647688994e-02  -6.28513446352642e-02  -6.33207245016290e-02  -6.37901043679938e-02  -6.42594842343586e-02  -6.47288641007234e-02  -6.51982439670882e-02  -6.56676238334530e-02  -6.61370036998178e-02  -6.66063835661826e-02  -6.70757634325474e-02  -6.75451432989121e-02  -6.80145231652769e-02  -6.84839030316417e-02  -6.89532828980065e-02  -6.94226627643713e-02  -7.02785907559777e-02  -7.09108730465514e-02  -7.13802529129162e-02  -7.18496327792810e-02  -7.23190126456458e-02  -7.27883925120106e-02  -7.32577723783754e-02  -7.37271522447402e-02  -7.41965321111050e-02  -7.46659119774698e-02  -7.51352918438346e-02  -7.56046717101994e-02  -7.60740515765641e-02  -7.65434314429289e-02  -7.73772709702358e-02  -7.83160307029654e-02  -7.90504721409244e-02  -7.95198520072892e-02  -7.99892318736540e-02  -8.04586117400188e-02  -8.09279916063836e-02  -8.13973714727484e-02  -8.18667513391131e-02  -8.23361312054779e-02  -8.28055110718427e-02  -8.33080236346568e-02  -8.42467833673864e-02  -8.47631012203876e-02  -8.52324810867525e-02  -8.57018609531172e-02  -8.61712408194820e-02  -8.66406206858468e-02  -8.71100005522116e-02  -8.75793804185764e-02  -8.80487602849412e-02  -8.85181401513060e-02  -8.89875200176708e-02  -8.94568998840356e-02  -8.99262797504004e-02  -9.03956596167651e-02  -9.08650394831299e-02  -9.13344193494947e-02  -9.21240819482026e-02  -9.28226296316749e-02  -9.32920094980397e-02  -9.37613893644044e-02  -9.42307692307692e-02
+  -1.88118811881188e-01  -1.86709123173624e-01  -1.74191916679105e-01  -1.67748810056885e-01  -1.66322536776291e-01  -1.62930991591621e-01  -1.54597243643962e-01  -1.51073021875052e-01  -1.48237059886893e-01  -1.42577574340349e-01  -1.39816242930826e-01  -1.33543128182165e-01  -1.23343615768612e-01  -1.19288687662736e-01  -1.16469310247608e-01  -1.14321608040201e-01  -1.12207074978855e-01  -1.10092541917508e-01  -1.08288969600478e-01  -1.06688558303066e-01  -1.04714994112477e-01  -1.04010149758694e-01  -1.03305305404912e-01  -1.02600461051130e-01  -1.01481002371594e-01  -9.91881851501733e-02  -9.63605154485298e-02  -9.56556710947477e-02  -9.49508267409656e-02  -9.23304642021991e-02  -8.95110867870707e-02  -8.78857986301143e-02  -8.71809542763322e-02  -8.63185564787635e-02  -8.49088677711992e-02  -8.34991790636350e-02  -8.08456473788082e-02  -7.95313199661675e-02  -7.80635852529977e-02  -7.62102592168765e-02  -7.45186327677994e-02  -7.16992553526709e-02  -6.88798779375425e-02  -6.78765112692174e-02  -6.57163706320381e-02  -6.32618538235733e-02  -6.16365656666169e-02  -6.09317213128348e-02  -6.02227308157951e-02  -5.88130421082309e-02  -5.62258487155248e-02  -5.48120138647031e-02  -5.41071695109209e-02  -5.31742872779740e-02  -5.18723982951059e-02  -5.11675539413238e-02  -4.97703036635322e-02  -4.83606149559680e-02  -4.74028558634758e-02  -4.63663200490903e-02  -4.47451780353915e-02  -4.28130752773770e-02  -4.21082309235949e-02  -4.14033865698128e-02  -3.56982934474352e-02  -3.16972652039073e-02  -3.02129459177073e-02  -2.93132328308208e-02  -2.79035441232565e-02  -2.64938554156923e-02  -2.57434034860772e-02  -2.50385591322951e-02  -2.43337147785130e-02  -2.33303481101879e-02  -2.20989435626980e-02  -2.13940992089159e-02  -2.06892548551338e-02  -1.93417582964327e-02  -1.79320695888684e-02  -1.69245567772858e-02  -1.62197124235036e-02  -1.55148680697215e-02  -1.47685622833640e-02  -1.33588735757998e-02  -1.19491848682356e-02  -1.05394961606714e-02  -9.51539877605851e-03  -8.81055442227639e-03  -8.10571006849429e-03  -7.37598885516691e-03  -5.96630014760270e-03  -5.16609449889712e-03  -4.46125014511502e-03  -3.01839229149045e-03  -1.40139642104913e-03  -4.39491185299433e-04   1.66674958953183e-03   3.07643829709604e-03   3.89322851883179e-03   5.07073320397366e-03   6.12799973464683e-03   7.52939615569600e-03   1.01248818349172e-02   1.15345705424814e-02   1.22477071827786e-02   1.35288654493590e-02   1.44824783985936e-02   1.55231603562366e-02   1.71484485131931e-02   1.90722589846924e-02   1.97771033384746e-02   2.25218501749672e-02   2.42217689105594e-02   2.56314576181236e-02   2.67218932948571e-02   2.80237822777253e-02   3.07643829709604e-02   3.28789160323068e-02   3.43300661724464e-02   3.62828996467486e-02   3.79745260958257e-02   3.96868832611905e-02   4.14365557158731e-02   4.21414000696552e-02   4.28462444234373e-02   4.41978871253960e-02   4.50810156392524e-02   4.61921820322736e-02   4.73157868550674e-02   4.90157055906596e-02   5.37215781879696e-02   5.51312668955338e-02   5.71711693782444e-02   5.82657511982354e-02   5.93603330182264e-02   6.13090203492711e-02   6.38298754498566e-02   6.52105411546180e-02   6.59153855084001e-02   6.78474882664146e-02   6.89752392324660e-02   7.04263893726056e-02   7.20350929565318e-02   7.27399373103140e-02   7.34447816640961e-02   7.41496260178782e-02   7.60485596298323e-02   7.72094797419440e-02   7.79143240957262e-02   7.90918287808681e-02   8.09741778197920e-02   8.16790221735742e-02   8.37852629484054e-02   8.53193359536959e-02   8.62688027596730e-02   8.73136308605735e-02   8.85035739754880e-02   8.92084183292701e-02   8.99132626830522e-02   9.06181070368343e-02   9.13229513906165e-02   9.20277957443986e-02   9.27326400981807e-02   9.36406454715824e-02   9.50503341791466e-02   9.64600228867108e-02   9.72021825298108e-02   9.79070268835929e-02   9.86118712373750e-02   9.93167155911571e-02   1.00208136391529e-01   1.01551486806972e-01   1.02256331160754e-01   1.02961175514536e-01   1.03666019868318e-01   1.04781332404597e-01   1.06481251140189e-01   1.08595784201536e-01   1.10760070981973e-01   1.13579448397101e-01   1.15764465893826e-01   1.17364877191237e-01   1.19562333117734e-01   1.21834419622867e-01   1.23090701029902e-01   1.23861883675805e-01   1.25976416737151e-01   1.29326500489245e-01   1.32353185067250e-01   1.35549861518815e-01   1.38045839759855e-01   1.38750684113638e-01   1.39488697613480e-01   1.41603230674826e-01   1.43717763736173e-01   1.45832296797519e-01   1.47586115395459e-01   1.49476756720898e-01   1.51935419672621e-01   1.52640264026403e-01
+  -2.74725274725275e-04   2.60919984538075e-04   7.96565243801425e-04   1.07819316362030e-03   1.34601579325197e-03   1.61383842288365e-03   1.88166105251532e-03   2.14948368214700e-03   2.41730631177867e-03   2.89773041029322e-03   3.43337566955657e-03   3.77022475012425e-03   4.03804737975592e-03   4.30587000938760e-03   4.57369263901927e-03   4.84151526865095e-03   5.10933789828262e-03   5.53454083604837e-03   6.07018609531172e-03   6.46225633662820e-03   6.73007896625987e-03   6.73836214037219e-03   6.47053951074051e-03   6.20271688110884e-03   5.93489425147717e-03   5.66707162184549e-03   5.39924899221382e-03   5.13142636258214e-03   4.86360373295047e-03   4.59578110331879e-03   4.32795847368712e-03   3.99939256723176e-03   3.46374730796841e-03   2.97504003534154e-03   2.70721740570987e-03   2.43939477607819e-03   2.17157214644652e-03   1.88442211055276e-03   1.34877685128941e-03   8.18653708100944e-04   5.50831078469268e-04   2.83008448837594e-04   1.51858192059204e-05  -2.52636810425756e-04  -5.20459440057430e-04  -7.88282069689105e-04  -1.05610469932078e-03  -1.32392732895246e-03  -1.80987354354189e-03  -2.34551880280523e-03  -2.67684576729803e-03  -2.94466839692970e-03  -3.21249102656138e-03  -3.48031365619305e-03  -3.74813628582473e-03  -4.01595891545640e-03  -4.44668396929703e-03  -4.98232922856038e-03  -5.36887735380198e-03  -5.63669998343365e-03  -5.90452261306533e-03  -6.17234524269700e-03  -6.56165442597603e-03  -7.09729968523939e-03  -7.52526368104258e-03  -7.79308631067425e-03  -8.15478491357888e-03  -8.69043017284223e-03  -9.38621679827710e-03  -1.04575073168038e-02  -1.13300016566348e-02  -1.15978242862665e-02  -1.18656469158982e-02  -1.21334695455298e-02  -1.24786018002098e-02  -1.32820696891049e-02  -1.40358385333260e-02  -1.43036611629576e-02  -1.45935722568888e-02  -1.53970401457839e-02  -1.62005080346789e-02  -1.64738527803854e-02  -1.67416754100171e-02  -1.70094980396488e-02  -1.72773206692805e-02  -1.75451432989121e-02  -1.78129659285438e-02  -1.83044342592081e-02  -1.88400795184715e-02  -1.95855651885803e-02  -2.03890330774753e-02  -2.09964658457121e-02  -2.15321111049754e-02  -2.26144458556519e-02  -2.39535590038103e-02  -2.49558230714010e-02  -2.57592909602960e-02  -2.64081395990944e-02  -2.69437848583577e-02  -2.73386161577116e-02  -2.76064387873433e-02  -2.82552874261417e-02  -2.93265779446684e-02  -3.22091225357557e-02  -3.75655751283892e-02  -4.51087856866751e-02  -5.63573361312055e-02  -6.42677674084709e-02  -6.50712352973660e-02  -6.60182782042078e-02  -6.73573913523662e-02  -6.86385222817384e-02  -6.97098128002651e-02  -7.06927494615937e-02  -7.12283947208570e-02  -7.17944116185322e-02  -7.25978795074272e-02  -7.33682146998730e-02  -7.36360373295047e-02  -7.39038599591363e-02  -7.41716825887680e-02  -7.44395052183997e-02  -7.52208846429952e-02  -7.60243525318902e-02  -7.73137666353747e-02  -7.86528797835331e-02  -7.93044894803689e-02  -7.98401347396322e-02  -8.01604174719753e-02  -8.04282401016069e-02  -8.08976199679717e-02  -8.14332652272351e-02  -8.17811585399525e-02  -8.20489811695842e-02  -8.23168037992159e-02  -8.25846264288475e-02  -8.28524490584792e-02  -8.31202716881109e-02  -8.33880943177426e-02  -8.36559169473742e-02  -8.39237395770059e-02  -8.41915622066376e-02  -8.44593848362693e-02  -8.47272074659009e-02  -8.49950300955326e-02  -8.52628527251643e-02  -8.55306753547960e-02  -8.57984979844276e-02  -8.61436302391076e-02  -8.66792754983710e-02  -8.71514164227732e-02  -8.74192390524049e-02  -8.76870616820366e-02  -8.79548843116682e-02  -8.82227069412999e-02  -8.84905295709316e-02  -8.87804406648628e-02  -8.93160859241261e-02  -8.98434480092771e-02  -9.01112706389088e-02  -9.03790932685405e-02  -9.01223148710586e-02  -8.98544922414269e-02  -8.95866696117952e-02  -8.93188469821636e-02  -8.90510243525319e-02  -8.87832017229002e-02  -8.85153790932685e-02  -8.82475564636369e-02  -8.79797338340052e-02  -8.77119112043735e-02  -8.74440885747418e-02  -8.71762659451102e-02  -8.69084433154785e-02  -8.66406206858468e-02  -8.63727980562152e-02  -8.61049754265835e-02  -8.58371527969518e-02  -8.55693301673201e-02  -8.53015075376884e-02  -8.50336849080568e-02  -8.47658622784251e-02  -8.44980396487934e-02  -8.42302170191618e-02  -8.39623943895301e-02  -8.38878458225192e-02  -8.41556684521509e-02  -8.42578275995361e-02  -8.39900049699045e-02  -8.37221823402728e-02  -8.34543597106411e-02  -8.31865370810094e-02  -8.29187144513778e-02  -8.26508918217461e-02  -8.23830691921144e-02  -8.21152465624827e-02  -8.18474239328511e-02  -8.15796013032194e-02  -8.13117786735877e-02  -8.10439560439560e-02
+  -1.86468646864686e-01  -1.80838184320945e-01  -1.75207721777203e-01  -1.72628820671012e-01  -1.70215765295122e-01  -1.68524138846045e-01  -1.66915435262119e-01  -1.65986699172430e-01  -1.65182347380467e-01  -1.63739489526842e-01  -1.62130785942916e-01  -1.60820604673533e-01  -1.59614076985588e-01  -1.58685340895899e-01  -1.57880989103936e-01  -1.56562515548037e-01  -1.54953811964111e-01  -1.53817768711545e-01  -1.53013416919581e-01  -1.50699868981873e-01  -1.47080285918039e-01  -1.43655571587309e-01  -1.40438164419457e-01  -1.37569033285238e-01  -1.35155977909349e-01  -1.32589515232930e-01  -1.29774283961059e-01  -1.27622435610395e-01  -1.26818083818432e-01  -1.26013732026469e-01  -1.25209380234506e-01  -1.24405028442543e-01  -1.23600676650580e-01  -1.22796324858617e-01  -1.21991973066653e-01  -1.21137867555600e-01  -1.19931339867655e-01  -1.18782858185316e-01  -1.18380682289334e-01  -1.17970214106838e-01  -1.17165862314875e-01  -1.16361510522912e-01  -1.15946896197157e-01  -1.15544720301176e-01  -1.14773537655273e-01  -1.13969185863310e-01  -1.13164834071347e-01  -1.12360482279384e-01  -1.11556130487421e-01  -1.10751778695457e-01  -1.09947426903494e-01  -1.09143075111531e-01  -1.08624807204339e-01  -1.08222631308357e-01  -1.07555102243893e-01  -1.06750750451930e-01  -1.06191021112161e-01  -1.05788845216180e-01  -1.05386669320198e-01  -1.04984493424217e-01  -1.04175995488996e-01  -1.02969467801051e-01  -1.02127800719770e-01  -1.01725624823789e-01  -1.01323448927807e-01  -1.00921273031826e-01  -1.00519097135844e-01  -1.00116921239863e-01  -9.97147453438811e-02  -9.93125694478996e-02  -9.89103935519180e-02  -9.85082176559365e-02  -9.81060417599549e-02  -9.77038658639733e-02  -9.73016899679918e-02  -9.68995140720102e-02  -9.64973381760287e-02  -9.60951622800471e-02  -9.56929863840655e-02  -9.52908104880840e-02  -9.48886345921024e-02  -9.44864586961209e-02  -9.40842828001393e-02  -9.36821069041577e-02  -9.32799310081762e-02  -9.28777551121946e-02  -9.24755792162131e-02  -9.20734033202315e-02  -9.16712274242500e-02  -9.09539446406952e-02  -9.01495928487321e-02  -8.96396172280545e-02  -8.92374413320729e-02  -8.88352654360913e-02  -8.84330895401098e-02  -8.80309136441282e-02  -8.76287377481467e-02  -8.72265618521651e-02  -8.68243859561836e-02  -8.64222100602020e-02  -8.60200341642204e-02  -8.56178582682389e-02  -8.52156823722573e-02  -8.48135064762758e-02  -8.44113305802942e-02  -8.40091546843127e-02  -8.36069787883311e-02  -8.30762724513657e-02  -8.22719206594026e-02  -8.15753685921356e-02  -8.11731926961540e-02  -8.07710168001725e-02  -8.03688409041909e-02  -7.99666650082094e-02  -7.95644891122278e-02  -7.91623132162462e-02  -7.87601373202647e-02  -7.83579614242831e-02  -7.79557855283016e-02  -7.75536096323200e-02  -7.71514337363385e-02  -7.67492578403569e-02  -7.63470819443753e-02  -7.59449060483938e-02  -7.55427301524122e-02  -7.51405542564307e-02  -7.47383783604491e-02  -7.43362024644676e-02  -7.39340265684860e-02  -7.35318506725044e-02  -7.28270063187223e-02  -7.20226545267592e-02  -7.15002404763089e-02  -7.10980645803274e-02  -7.04346816591207e-02  -6.96303298671576e-02  -6.90664543841319e-02  -6.86642784881503e-02  -6.82621025921688e-02  -6.78599266961872e-02  -6.74577508002056e-02  -6.70555749042241e-02  -6.66533990082425e-02  -6.62512231122610e-02  -6.56914937724928e-02  -6.48871419805297e-02  -6.42196129160655e-02  -6.38174370200839e-02  -6.32991691128912e-02  -6.24948173209281e-02  -6.14997429391180e-02  -5.98910393551918e-02  -5.79838134567225e-02  -5.47664062888701e-02  -5.16028989833657e-02  -4.87876677114948e-02  -4.60056055856842e-02  -4.35925502097948e-02  -4.11670564041329e-02  -3.83518251322619e-02  -3.55365938603910e-02  -3.15397117601208e-02  -2.75179528003052e-02  -2.64814169859197e-02  -2.56770651939566e-02  -2.48727134019935e-02  -2.40683616100303e-02  -2.29323183574639e-02  -2.17257906695192e-02  -1.86534985156807e-02  -1.50339154518467e-02  -1.34459425842082e-02  -1.26415907922450e-02  -1.21067383120222e-02  -1.17045624160406e-02  -1.03073121382490e-02  -8.29643265834122e-03  -6.51359105759823e-03  -4.90488747367199e-03  -2.67426240111447e-03   1.40968870756449e-04   1.83674146309104e-03   2.23891735907259e-03   3.47032190656250e-03   5.88337728245186e-03   1.00378128265088e-02   1.72769789541769e-02   2.33966864023086e-02   2.70162694661426e-02   3.00139310413453e-02   3.12204587292900e-02   3.25099092823855e-02   3.41186128663118e-02   3.56651243013749e-02   3.68716519893195e-02   3.79952568121134e-02   3.83974327080949e-02   3.87996086040765e-02   3.92017845000580e-02   3.96039603960396e-02
+   8.24175824175824e-04   1.08923739577006e-03   1.35429896736429e-03   1.61936053895853e-03   1.88442211055276e-03   2.14948368214700e-03   2.41454525374123e-03   2.26544811971948e-03   2.00038654812524e-03   1.73532497653101e-03   1.47026340493677e-03   1.20520183334254e-03   9.40140261748302e-04   9.73272958197581e-04   1.23833452979182e-03   1.50339610138605e-03   1.76845767298029e-03   2.03351924457452e-03   2.29858081616876e-03   2.56364238776299e-03   2.82870395935723e-03   3.09376553095146e-03   3.35882710254570e-03   3.67634877685129e-03   4.20647192003976e-03   4.70346236677895e-03   4.96852393837318e-03   5.23358550996742e-03   5.49864708156165e-03   5.76370865315589e-03   6.02877022475012e-03   6.29383179634436e-03   6.55889336793859e-03   6.82395493953283e-03   7.08901651112706e-03   7.35407808272130e-03   7.61913965431553e-03   7.88420122590977e-03   8.14926279750400e-03   8.41432436909824e-03   8.67938594069247e-03   8.94444751228671e-03   9.20950908388094e-03   9.47457065547518e-03   9.73963222706941e-03   1.00046937986636e-02   1.02697553702579e-02   1.05348169418521e-02   1.07998785134464e-02   1.10649400850406e-02   1.13300016566348e-02   1.15950632282291e-02   1.21886907062786e-02   1.43091832790325e-02   1.63192335302888e-02   1.73794798166657e-02   1.84148765807057e-02   1.86799381523000e-02   1.89449997238942e-02   1.97180959743774e-02   2.05132806891601e-02   2.08390855375780e-02   2.11041471091722e-02   2.30921088961290e-02   2.54776630404771e-02   2.68830415815340e-02   2.79432878679110e-02   2.91802418686841e-02   3.05055497266553e-02   3.19882378927605e-02   3.35786073223259e-02   3.53070296537633e-02   3.71624606549230e-02   4.09174995858413e-02   4.70139157325087e-02   5.14205643602628e-02   5.30109337898282e-02   5.42009498039649e-02   5.44660113755591e-02   5.47918162239770e-02   5.53219393671655e-02   5.59348942514772e-02   5.69951405378541e-02   5.80553868242310e-02   5.91156331106080e-02   6.01731183389475e-02   6.09683030537302e-02   6.17634877685129e-02   6.23101772599260e-02   6.28403004031145e-02   6.31412557291954e-02   6.34063173007897e-02   6.38812192832293e-02   6.44113424264178e-02   6.47509525650229e-02   6.50160141366171e-02   6.52810757082114e-02   6.55461372798056e-02   6.61149152355183e-02   6.69100999503009e-02   6.74402230934894e-02   6.77052846650837e-02   6.80835496162129e-02   6.86136727594014e-02   6.92376718758628e-02   7.00328565906455e-02   7.06789441714065e-02   7.09440057430007e-02   7.12090673145949e-02   7.14741288861892e-02   7.17391904577834e-02   7.20042520293776e-02   7.22858799491965e-02   7.28160030923850e-02   7.33461262355735e-02   7.36139488652051e-02   7.38790104367994e-02   7.41440720083936e-02   7.44091335799878e-02   7.48978408526147e-02   7.54279639958032e-02   7.57537688442211e-02   7.60188304158153e-02   7.62838919874096e-02   7.65489535590038e-02   7.68140151305980e-02   7.70790767021923e-02   7.74904743497708e-02   7.80205974929593e-02   7.84237119664255e-02   7.86887735380198e-02   7.89538351096140e-02   7.92188966812082e-02   7.94839582528025e-02   7.97490198243967e-02   8.00831078469269e-02   8.06132309901154e-02   8.10936550886299e-02   8.13587166602242e-02   8.16237782318184e-02   8.18888398034127e-02   8.21539013750069e-02   8.24189629466011e-02   8.26840245181954e-02   8.29490860897896e-02   8.32141476613838e-02   8.39541112154178e-02   8.47492959302004e-02   8.53263570600254e-02   8.58564802032139e-02   8.61878071677067e-02   8.64528687393009e-02   8.67179303108951e-02   8.69829918824894e-02   8.72480534540836e-02   8.75131150256778e-02   8.77781765972721e-02   8.80432381688663e-02   8.83082997404605e-02   8.85733613120548e-02   8.88384228836490e-02   8.91034844552432e-02   8.93685460268375e-02   8.96336075984317e-02   8.98986691700260e-02   9.01637307416202e-02   9.04287923132144e-02   9.06938538848086e-02   9.09589154564029e-02   9.12239770279971e-02   9.14890385995913e-02   9.17541001711856e-02   9.20191617427798e-02   9.22842233143741e-02   9.25492848859683e-02   9.28143464575625e-02   9.30794080291568e-02   9.33444696007510e-02   9.36095311723452e-02   9.38745927439395e-02   9.41396543155337e-02   9.44047158871279e-02   9.46697774587222e-02   9.49348390303164e-02   9.51999006019107e-02   9.54649621735049e-02   9.57300237450991e-02   9.59950853166933e-02   9.62601468882876e-02   9.65252084598818e-02   9.67902700314761e-02   9.70553316030703e-02   9.73203931746645e-02   9.75854547462588e-02   9.78505163178530e-02   9.81155778894472e-02   9.83806394610415e-02   9.86457010326357e-02   9.89107626042299e-02   9.91758241758242e-02
+  -1.91419141914191e-01  -1.78682189827023e-01  -1.65945237739854e-01  -1.64647494900244e-01  -1.64249465147520e-01  -1.57391744199546e-01  -1.49431149145065e-01  -1.39604789624691e-01  -1.29256016053867e-01  -1.25955686020863e-01  -1.25557656268139e-01  -1.22630479128315e-01  -1.18252151848351e-01  -1.10739340265685e-01  -1.00788596447584e-01  -9.49300960246778e-02  -9.33379770137818e-02  -9.17458580028857e-02  -9.01537389919896e-02  -8.84247972535947e-02  -8.64346484899746e-02  -8.45522994510506e-02  -8.29601804401546e-02  -8.16043915949384e-02  -8.12063618422144e-02  -8.07585783703999e-02  -7.99625188649518e-02  -7.91871900757915e-02  -7.87891603230675e-02  -7.83911305703435e-02  -7.79931008176195e-02  -7.75950710648954e-02  -7.71970413121714e-02  -7.67990115594474e-02  -7.64009818067234e-02  -7.60029520539994e-02  -7.56049223012754e-02  -7.52068925485513e-02  -7.48088627958273e-02  -7.44108330431033e-02  -7.40128032903793e-02  -7.36147735376553e-02  -7.32167437849313e-02  -7.28187140322072e-02  -7.24206842794832e-02  -7.20226545267592e-02  -7.16246247740352e-02  -7.12265950213112e-02  -7.08285652685872e-02  -7.04305355158631e-02  -7.00325057631391e-02  -6.96344760104151e-02  -6.92364462576911e-02  -6.88384165049671e-02  -6.83989253196676e-02  -6.76028658142196e-02  -6.68192447385442e-02  -6.64212149858202e-02  -6.60231852330962e-02  -6.56251554803721e-02  -6.52271257276481e-02  -6.48290959749241e-02  -6.44310662222001e-02  -6.37096372953878e-02  -6.29135777899398e-02  -6.24118944557772e-02  -6.20138647030532e-02  -6.16158349503292e-02  -6.12178051976052e-02  -6.08197754448812e-02  -6.04217456921572e-02  -5.98164087765561e-02  -5.90203492711080e-02  -5.84025739257343e-02  -5.80045441730103e-02  -5.76065144202863e-02  -5.72084846675622e-02  -5.68104549148382e-02  -5.64124251621142e-02  -5.59231802577243e-02  -5.51271207522762e-02  -5.43932533956913e-02  -5.39952236429673e-02  -5.35971938902433e-02  -5.31991641375193e-02  -5.28011343847953e-02  -5.24031046320712e-02  -5.20050748793472e-02  -5.16070451266232e-02  -5.12090153738992e-02  -5.08109856211752e-02  -5.04129558684512e-02  -5.00149261157272e-02  -4.96168963630031e-02  -4.92188666102791e-02  -4.88208368575551e-02  -4.84228071048311e-02  -4.80247773521071e-02  -4.76267475993831e-02  -4.72287178466590e-02  -4.66316732175730e-02  -4.58356137121250e-02  -4.52095460802362e-02  -4.48115163275122e-02  -4.44134865747881e-02  -4.40154568220641e-02  -4.36174270693401e-02  -4.32193973166161e-02  -4.28213675638921e-02  -4.24233378111681e-02  -4.20253080584440e-02  -4.16272783057200e-02  -4.12292485529960e-02  -4.08312188002720e-02  -4.04331890475480e-02  -4.00351592948240e-02  -3.96371295420999e-02  -3.92390997893759e-02  -3.88410700366519e-02  -3.81072026800670e-02  -3.73111431746190e-02  -3.68218982702290e-02  -3.64238685175050e-02  -3.60258387647810e-02  -3.56278090120570e-02  -3.52297792593330e-02  -3.48317495066090e-02  -3.39942285685855e-02  -3.28001393104135e-02  -3.19874952319353e-02  -3.15894654792112e-02  -3.11914357264872e-02  -3.07934059737632e-02  -3.02626996367979e-02  -2.94666401313498e-02  -2.87742342073403e-02  -2.83762044546163e-02  -2.79781747018923e-02  -2.75801449491683e-02  -2.71821151964443e-02  -2.67840854437203e-02  -2.63860556909962e-02  -2.59880259382722e-02  -2.55899961855482e-02  -2.44207837869214e-02  -2.32266945287494e-02  -2.20326052705773e-02  -2.08385160124053e-02  -2.02995173889248e-02  -1.99014876362008e-02  -1.95034578834768e-02  -1.91054281307528e-02  -1.81683997545483e-02  -1.69743104963763e-02  -1.60206975471416e-02  -1.52246380416936e-02  -1.44285785362456e-02  -1.36325190307976e-02  -1.26540292220177e-02  -1.14599399638456e-02  -1.05726653067317e-02  -1.01746355540077e-02  -9.65222150355741e-03  -8.85616199810937e-03  -7.77401860789093e-03  -5.78386984427089e-03  -3.99273595701279e-03  -3.19667645156477e-03  -2.10209463157375e-03   1.87820289566646e-03   5.78386984427085e-03   6.18189959699487e-03   6.57992934971888e-03   7.73255717531551e-03   8.92664643348757e-03   1.01207356916596e-02   1.13148249498317e-02   1.31474202696651e-02   1.51375690332852e-02   1.65472577408495e-02   1.77413469990215e-02   1.84130222067433e-02   1.88110519594673e-02   1.92090817121913e-02   1.96071114649153e-02   2.04114632568784e-02   2.16055525150505e-02   2.24513657395890e-02   2.28493954923130e-02   2.32474252450371e-02   2.36454549977611e-02   2.40434847504851e-02   2.44415145032091e-02   2.48395442559331e-02   2.52375740086571e-02   2.56356037613812e-02   2.60336335141052e-02   2.64316632668292e-02   2.68296930195532e-02   2.72277227722772e-02
+   8.24175824175824e-04   7.05450328565907e-04   5.86724832955989e-04   4.67999337346071e-04   3.49273841736153e-04   2.30548346126236e-04   1.11822850516318e-04  -6.90264509359987e-06  -1.25628140703518e-04  -2.44353636313435e-04  -1.86371417527197e-04  -6.76459219172787e-05   5.10795736926391e-05   1.69805069302557e-04   2.88530564912474e-04   4.07256060522392e-04   5.25981556132310e-04   6.44707051742228e-04   7.63432547352145e-04   8.82158042962063e-04   1.00088353857198e-03   1.11960903418190e-03   1.23833452979182e-03   1.35706002540173e-03   1.47578552101165e-03   1.59451101662157e-03   1.71323651223149e-03   1.83196200784140e-03   1.89546634270252e-03   1.77674084709261e-03   1.65801535148269e-03   1.53928985587277e-03   1.42056436026285e-03   1.30183886465294e-03   1.18311336904302e-03   1.06438787343310e-03   9.45662377823182e-04   8.26936882213264e-04   7.08211386603346e-04   5.89485890993429e-04   4.70760395383511e-04   3.52034899773594e-04   2.33309404163675e-04   1.14583908553758e-04  -4.14158705615985e-06  -1.22867082666077e-04  -2.41592578275995e-04  -3.60318073885913e-04  -4.79043569495831e-04  -5.97769065105749e-04  -7.16494560715666e-04  -8.46264288475343e-04  -1.08371527969518e-03  -1.32116627091501e-03  -1.55861726213485e-03  -1.79606825335469e-03  -1.97829808382572e-03  -2.09702357943564e-03  -2.21574907504556e-03  -2.33447457065547e-03  -2.45320006626539e-03  -2.57192556187531e-03  -2.69065105748523e-03  -2.80937655309515e-03  -2.92810204870506e-03  -3.04682754431498e-03  -3.16555303992490e-03  -3.28427853553482e-03  -3.40300403114473e-03  -3.52172952675465e-03  -3.64045502236457e-03  -3.75918051797449e-03  -3.87790601358440e-03  -3.99663150919432e-03  -4.11535700480424e-03  -4.23408250041416e-03  -4.35280799602408e-03  -4.47153349163399e-03  -4.59025898724391e-03  -4.70898448285383e-03  -4.82770997846375e-03  -4.94643547407366e-03  -5.06516096968358e-03  -5.18388646529350e-03  -5.30261196090342e-03  -5.42133745651334e-03  -5.54006295212325e-03  -5.65878844773317e-03  -5.77751394334309e-03  -5.89623943895301e-03  -6.01496493456292e-03  -6.13369043017284e-03  -6.25241592578276e-03  -6.37114142139268e-03  -6.48986691700259e-03  -6.60859241261251e-03  -6.72731790822243e-03  -6.84604340383235e-03  -6.96476889944227e-03  -7.08349439505218e-03  -7.20221989066210e-03  -7.32094538627202e-03  -7.43967088188194e-03  -7.55839637749185e-03  -7.67712187310177e-03  -7.79584736871169e-03  -7.91457286432161e-03  -8.03329835993153e-03  -8.15202385554144e-03  -8.27074935115136e-03  -8.38947484676128e-03  -8.50820034237120e-03  -8.62692583798111e-03  -8.74565133359103e-03  -8.86437682920095e-03  -8.98310232481087e-03  -9.13772157490750e-03  -9.37517256612734e-03  -9.61262355734717e-03  -9.85007454856701e-03  -1.00875255397868e-02  -1.02449058479209e-02  -1.03636313435308e-02  -1.04823568391408e-02  -1.06010823347507e-02  -1.07198078303606e-02  -1.08385333259705e-02  -1.09572588215804e-02  -1.10759843171903e-02  -1.11947098128003e-02  -1.13134353084102e-02  -1.14321608040201e-02  -1.15508862996300e-02  -1.16696117952399e-02  -1.17883372908499e-02  -1.19070627864598e-02  -1.20257882820697e-02  -1.21445137776796e-02  -1.22632392732895e-02  -1.23819647688994e-02  -1.25006902645094e-02  -1.26194157601193e-02  -1.27381412557292e-02  -1.28568667513391e-02  -1.29755922469490e-02  -1.30943177425589e-02  -1.32130432381689e-02  -1.33317687337788e-02  -1.34504942293887e-02  -1.35692197249986e-02  -1.36879452206085e-02  -1.38066707162185e-02  -1.39253962118284e-02  -1.40441217074383e-02  -1.41628472030482e-02  -1.42815726986581e-02  -1.44002981942680e-02  -1.45190236898780e-02  -1.47150588105362e-02  -1.49525098017560e-02  -1.51899607929759e-02  -1.54274117841957e-02  -1.56621017173781e-02  -1.57808272129880e-02  -1.58995527085979e-02  -1.60182782042078e-02  -1.61370036998178e-02  -1.62557291954277e-02  -1.63744546910376e-02  -1.64931801866475e-02  -1.66119056822574e-02  -1.67306311778674e-02  -1.68493566734773e-02  -1.69680821690872e-02  -1.70868076646971e-02  -1.72055331603070e-02  -1.73242586559169e-02  -1.74429841515269e-02  -1.75617096471368e-02  -1.76804351427467e-02  -1.77991606383566e-02  -1.79178861339665e-02  -1.80366116295765e-02  -1.81553371251864e-02  -1.82740626207963e-02  -1.83927881164062e-02  -1.85115136120161e-02  -1.86302391076260e-02  -1.87489646032360e-02  -1.88676900988459e-02  -1.89256723176321e-02  -1.88069468220222e-02  -1.86882213264123e-02  -1.85694958308024e-02  -1.84507703351924e-02  -1.84811419736043e-02  -1.85998674692142e-02  -1.87185929648241e-02  -1.88373184604340e-02  -1.89560439560440e-02
+  -1.89768976897690e-01  -1.85490157055907e-01  -1.81211337214123e-01  -1.76932517372340e-01  -1.72653697530557e-01  -1.67976847936050e-01  -1.62628323133821e-01  -1.57279798331592e-01  -1.51931273529363e-01  -1.46582748727134e-01  -1.37121249813424e-01  -1.26245916048891e-01  -1.15370582284359e-01  -1.04495248519827e-01  -9.48637577325572e-02  -9.46854735724829e-02  -9.45071894124086e-02  -9.43289052523343e-02  -9.41506210922600e-02  -9.32757848649187e-02  -9.16712274242500e-02  -9.00666699835813e-02  -8.84621125429126e-02  -8.68575551022439e-02  -8.61734414647495e-02  -8.56385889845266e-02  -8.51037365043037e-02  -8.45688840240808e-02  -8.28731114317462e-02  -7.73463024694429e-02  -7.18194935071397e-02  -6.62926845448364e-02  -6.07658755825331e-02  -5.84730583611125e-02  -5.82947742010382e-02  -5.81164900409639e-02  -5.79382058808896e-02  -5.77599217208153e-02  -5.63626714430237e-02  -5.49363981624293e-02  -5.35101248818349e-02  -5.20838516012405e-02  -5.06575783206461e-02  -4.92313050400517e-02  -4.78050317594574e-02  -4.63787584788630e-02  -4.49524851982686e-02  -4.40403336816094e-02  -4.33271970413122e-02  -4.26140604010150e-02  -4.19009237607178e-02  -4.11712025473904e-02  -4.02797817470189e-02  -3.93883609466474e-02  -3.84969401462759e-02  -3.76055193459044e-02  -3.69628671409855e-02  -3.66062988208369e-02  -3.62497305006883e-02  -3.58931621805397e-02  -3.55365938603911e-02  -3.44337197538849e-02  -3.31857306333648e-02  -3.19377415128448e-02  -3.06897523923247e-02  -2.94044479824867e-02  -2.79781747018923e-02  -2.65519014212979e-02  -2.51256281407035e-02  -2.36993548601091e-02  -2.21694279980762e-02  -2.05648705574075e-02  -1.89603131167388e-02  -1.73557556760701e-02  -1.57511982354014e-02  -1.55065757832065e-02  -1.53282916231322e-02  -1.51500074630579e-02  -1.49717233029836e-02  -1.43290710980646e-02  -1.27245136573959e-02  -1.11199562167272e-02  -9.51539877605853e-03  -7.91084133538984e-03  -6.55505249017364e-03  -5.30706336965354e-03  -4.05907424913345e-03  -2.81108512861336e-03  -1.58797286763852e-03  -6.96552067267031e-04   1.94868733104463e-04   1.08628953347596e-03   1.97771033384745e-03   2.71157769043236e-03   3.24643017065525e-03   3.78128265087815e-03   4.31613513110105e-03   4.85098761132395e-03   5.09561006351892e-03   5.27389422359321e-03   5.45217838366751e-03   5.63046254374181e-03   5.87508499593678e-03   6.40993747615967e-03   6.94478995638257e-03   7.47964243660547e-03   8.01449491682836e-03   8.54934739705126e-03   9.08419987727415e-03   9.61905235749706e-03   1.01539048377200e-02   1.06887573179429e-02   1.10577640678641e-02   1.14143323880127e-02   1.17709007081613e-02   1.21274690283099e-02   1.26457369355026e-02   1.35371577358741e-02   1.44285785362456e-02   1.53199993366171e-02   1.62114201369886e-02   1.68623646284226e-02   1.73972171086455e-02   1.79320695888684e-02   1.84669220690913e-02   1.89851899762841e-02   1.91634741363584e-02   1.93417582964327e-02   1.95200424565070e-02   1.96983266165813e-02   2.01005025125628e-02   2.08136391528600e-02   2.15267757931572e-02   2.22399124334544e-02   2.29530490737516e-02   2.35252168432924e-02   2.40600693235153e-02   2.45949218037382e-02   2.51297742839611e-02   2.56065807585784e-02   2.57848649186527e-02   2.59631490787270e-02   2.61414332388013e-02   2.63197173988756e-02   2.67840854437202e-02   2.74972220840174e-02   2.82103587243146e-02   2.89234953646118e-02   2.96366320049090e-02   3.03497686452062e-02   3.10629052855034e-02   3.17760419258006e-02   3.24891785660978e-02   3.38491135545715e-02   3.68799442758346e-02   3.99107749970977e-02   4.29416057183608e-02   4.59724364396238e-02   4.96998192281539e-02   5.38003549098628e-02   5.79008905915717e-02   6.20014262732805e-02   6.60646466656716e-02   6.85606249067117e-02   7.10566031477519e-02   7.35525813887921e-02   7.60485596298323e-02   7.78396935170904e-02   7.85528301573876e-02   7.92659667976848e-02   7.99791034379820e-02   8.06922400782792e-02   8.15421994460753e-02   8.24336202464468e-02   8.33250410468183e-02   8.42164618471897e-02   8.50581289284707e-02   8.55929814086936e-02   8.61278338889165e-02   8.66626863691394e-02   8.71975388493623e-02   8.75499610262534e-02   8.77282451863277e-02   8.79065293464020e-02   8.80848135064763e-02   8.82630976665506e-02   8.92291490455578e-02   9.02988540060036e-02   9.13685589664494e-02   9.24382639268952e-02   9.33711461598421e-02   9.39059986400650e-02   9.44408511202879e-02   9.49757036005108e-02   9.55105560807337e-02   9.72768131084465e-02   9.97727913494867e-02   1.02268769590527e-01   1.04764747831567e-01   1.07260726072607e-01
diff --git a/src/demo_TPGMR01.cpp b/src/demo_TPGMR01.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..586eb41a80c1a0468c71c05c95a3ca2a310f5ec9
--- /dev/null
+++ b/src/demo_TPGMR01.cpp
@@ -0,0 +1,1940 @@
+/*
+ * demo_TPGMR01.cpp
+ *
+ * TP-GMM with GMR (conditioning on the phase of the demonstration)
+ *
+ * @article{Calinon16JIST,
+ *   author="Calinon, S.",
+ *   title="A Tutorial on Task-Parameterized Movement Learning and Retrieval",
+ *   journal="Intelligent Service Robotics",
+ *   publisher="Springer Berlin Heidelberg",
+ *   doi="10.1007/s11370-015-0187-9",
+ *   year="2016",
+ *   volume="9",
+ *   number="1",
+ *   pages="1--29"
+ * }
+ *
+ * Authors: Sylvain Calinon, Philip Abbet, Andras Kupcsik
+ */
+
+
+#include <stdio.h>
+#include <float.h>
+#include <armadillo>
+#include <chrono>
+
+#include <gfx2.h>
+#include <gfx_ui.h>
+#include <GLFW/glfw3.h>
+#include <imgui.h>
+#include <imgui_impl_glfw_gl2.h>
+#include <window_utils.h>
+
+#define IMGUI_DEFINE_MATH_OPERATORS
+#include <imgui_internal.h>
+
+using namespace arma;
+
+
+/***************************** ALGORITHM SECTION *****************************/
+
+typedef std::vector<vec> vector_list_t;
+typedef std::vector<mat> matrix_list_t;
+
+
+//-----------------------------------------------------------------------------
+// Contains all the parameters used by the algorithm. Some of them are
+// modifiable through the UI, others are hard-coded.
+//-----------------------------------------------------------------------------
+struct parameters_t {
+    int	   nb_states;		// Number of components in the GMM
+    int	   nb_frames;		// Number of candidate frames of reference
+    int	   nb_deriv;		// Number of static and dynamic features
+    int	   nb_data;			// Number of datapoints in a trajectory <==== not used for product of Gaussians!!!
+    float  dt;				// Time step duration					<==== not used for product of Gaussians!!!
+};
+
+//-----------------------------------------------------------------------------
+// Model trained using the algorithm
+//-----------------------------------------------------------------------------
+struct model_t {
+    parameters_t			   parameters;	// Parameters used to train the model
+
+    // These lists contain one element per GMM state and per frame (access them
+    // by doing: mu[state][frame])
+    std::vector<vector_list_t> mu;
+    std::vector<matrix_list_t> sigma;
+
+    int						   nb_var;
+    mat						   pix;
+    vec						   priors;
+};
+
+
+//-----------------------------------------------------------------------------
+// Represents a coordinate system, aka a reference frame
+//-----------------------------------------------------------------------------
+struct coordinate_system_t {
+
+    coordinate_system_t(const arma::vec& position, const arma::mat& orientation,
+                        const parameters_t& parameters) {
+
+        this->position = zeros(2 + (parameters.nb_deriv - 1) * 2);
+        this->position(span(0, 1)) = position(span(0, 1));
+
+        this->orientation = kron(eye(parameters.nb_deriv, parameters.nb_deriv),
+                                 orientation(span(0, 1), span(0, 1)));
+    }
+
+    vec position;
+    mat orientation;
+};
+
+
+//-----------------------------------------------------------------------------
+// Represents a list of coordinate systems
+//-----------------------------------------------------------------------------
+typedef std::vector<coordinate_system_t> coordinate_system_list_t;
+
+
+//-----------------------------------------------------------------------------
+// Contains all the needed informations about a demonstration, like:
+//	 - its reference frames
+//	 - the trajectory originally drawn by the user
+//	 - the resampled trajectory
+//	 - the trajectory expressed in each reference frame
+//-----------------------------------------------------------------------------
+class Demonstration
+{
+public:
+    Demonstration(coordinate_system_list_t coordinate_systems,
+                  const std::vector<arma::vec>& points,
+                  const parameters_t& parameters)
+            : coordinate_systems(coordinate_systems)
+    {
+        points_original = mat(3, points.size()); // added one for time (3rd dime)
+
+        for (size_t i = 0; i < points.size(); ++i) {
+            points_original(0, i) = points[i](0);
+            points_original(1, i) = points[i](1);
+            points_original(2, i) = points[i](2);
+        }
+
+        update(parameters);
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Resample the trajectory and recompute it in each reference frame
+    // according to the provided parameters
+    //-------------------------------------------------------------------------
+    void update(const parameters_t& parameters)
+    {
+        // Resampling of the trajectory
+        arma::vec x = points_original.row(0).t();
+        arma::vec y = points_original.row(1).t();
+        arma::vec x2(parameters.nb_data);
+        arma::vec y2(parameters.nb_data);
+
+        arma::vec from_indices = arma::linspace<arma::vec>(0, points_original.n_cols - 1, points_original.n_cols);
+        arma::vec to_indices = arma::linspace<arma::vec>(0, points_original.n_cols - 1, parameters.nb_data);
+
+        interp1(from_indices, x, to_indices, x2, "*linear");
+        interp1(from_indices, y, to_indices, y2, "*linear");
+
+        points = mat(2 * parameters.nb_deriv, parameters.nb_data);
+        points(span(0), span::all) = x2.t();
+        points(span(1), span::all) = y2.t();
+//        points = join_linspace(0, parameters.nb_data-1, parameters.nb_data);
+
+
+        // Compute the derivatives
+        mat D = (diagmat(ones(1, parameters.nb_data - 1), -1) -
+                 eye(parameters.nb_data, parameters.nb_data)) / parameters.dt;
+
+        D(parameters.nb_data - 1, parameters.nb_data - 1) = 0.0;
+
+        points(span(2, 3), span::all) = points(span(0, 1), span::all) * pow(D, 1);
+
+        // Compute the points in each coordinate system
+        points_in_coordinate_systems.clear();
+
+
+        points = join_vert(points, linspace(0, points.n_cols-1, points.n_cols).t());
+
+        for (int m = 0; m < coordinate_systems.size(); ++m) {
+            points_in_coordinate_systems.push_back(
+                    join_vert( pinv(coordinate_systems[m].orientation) *
+                    (points.rows(0, points.n_rows-2) - repmat(coordinate_systems[m].position, 1, parameters.nb_data)), points.row(points.n_rows-1)));
+        }
+    }
+
+
+    //-------------------------------------------------------------------------
+    // Returns the coordinates of a point in a specific reference frame of
+    // the demonstration
+    //-------------------------------------------------------------------------
+    arma::vec convert_to_coordinate_system(const arma::vec& point, int frame) const {
+        vec original_point = zeros(points.n_rows);
+        original_point(span(0, 1)) = point(span(0, 1));
+
+        vec result = pinv(coordinate_systems[frame].orientation) *
+                     (original_point - coordinate_systems[frame].position);
+
+        return result(span(0, 1));
+    }
+
+
+public:
+    coordinate_system_list_t coordinate_systems;
+    arma::mat				 points_original;
+    arma::mat				 points;
+    matrix_list_t			 points_in_coordinate_systems;
+};
+
+
+//-----------------------------------------------------------------------------
+// Represents a list of demonstrations
+//-----------------------------------------------------------------------------
+typedef std::vector<Demonstration> demonstration_list_t;
+
+
+//-----------------------------------------------------------------------------
+// Computes the factorial of a number
+//-----------------------------------------------------------------------------
+int factorial(int n) {
+    return (n == 1 || n == 0) ? 1 : factorial(n - 1) * n;
+}
+
+
+//-----------------------------------------------------------------------------
+// Return the likelihood of datapoint(s) to be generated by a Gaussian
+// parameterized by center and covariance
+//-----------------------------------------------------------------------------
+arma::vec gaussPDF(const mat& data, colvec mu, mat sigma) {
+
+    int nb_var = data.n_rows;
+    int nb_data = data.n_cols;
+
+    mat data2 = data.t() - repmat(mu.t(), nb_data, 1);
+
+    vec prob = sum((data2 * inv(sigma)) % data2, 1);
+
+    prob = exp(-0.5 * prob) / sqrt(pow((2 * datum::pi), nb_var) * det(sigma) + DBL_MIN);
+
+    return prob;
+}
+
+
+//-----------------------------------------------------------------------------
+// Initialization of Gaussian Mixture Model (GMM) parameters by clustering an
+// ordered dataset into equal bins
+//-----------------------------------------------------------------------------
+void init_tensorGMM_kbins(const demonstration_list_t& demos,
+                          model_t &model) {
+
+    model.priors.resize(model.parameters.nb_states);
+    model.mu.clear();
+    model.sigma.clear();
+
+    model.nb_var = demos[0].points_in_coordinate_systems[0].n_rows;
+
+    // Initialize bins
+    uvec t_sep = linspace<uvec>(0, model.parameters.nb_data - 1,
+                                model.parameters.nb_states + 1);
+
+    struct bin_t {
+        mat data;
+        vec mu;
+        mat sigma;
+    };
+
+    std::vector<bin_t> bins;
+    for (int i = 0; i < model.parameters.nb_states; ++i) {
+        bin_t bin;
+        bin.data = zeros(model.nb_var * model.parameters.nb_frames + 1, //adding time as last dimension
+                         demos.size() * (t_sep(i + 1) - t_sep(i) + 1));
+
+        bins.push_back(bin);
+    }
+
+
+    // Split each demonstration in K equal bins
+    for (int n = 0; n < demos.size(); ++n) {
+
+        for (int i = 0; i < model.parameters.nb_states; ++i) {
+            int bin_size = t_sep(i + 1) - t_sep(i) + 1;
+
+            for (int m = 0; m < model.parameters.nb_frames; ++m) {
+                bins[i].data(span(m * model.nb_var, (m + 1) * model.nb_var - 1),
+                             span(n * bin_size, (n + 1) * bin_size - 1)) =
+                        demos[n].points_in_coordinate_systems[m](span::all, span(t_sep(i), t_sep(i + 1)));
+            }
+        }
+    }
+
+
+    // Calculate statistics on bin data
+    for (int i = 0; i < model.parameters.nb_states; ++i) {
+        bins[i].mu = mean(bins[i].data, 1);
+        bins[i].sigma = cov(bins[i].data.t());
+        model.priors(i) = bins[i].data.n_elem;
+    }
+
+
+    // Reshape GMM into a tensor
+    for (int i = 0; i < model.parameters.nb_states; ++i) {
+        model.mu.push_back(vector_list_t());
+        model.sigma.push_back(matrix_list_t());
+    }
+
+    for (int m = 0; m < model.parameters.nb_frames; ++m) {
+        for (int i = 0; i < model.parameters.nb_states; ++i) {
+            model.mu[i].push_back(bins[i].mu(span(m * model.nb_var, (m + 1) * model.nb_var - 1)));
+
+            model.sigma[i].push_back(bins[i].sigma(span(m * model.nb_var, (m + 1) * model.nb_var - 1),
+                                                   span(m * model.nb_var, (m + 1) * model.nb_var - 1)));
+
+        }
+
+    }
+
+    model.priors /= sum(model.priors);
+}
+
+
+//-----------------------------------------------------------------------------
+// Training of a task-parameterized Gaussian mixture model (GMM) with an
+// expectation-maximization (EM) algorithm.
+//
+// The approach allows the modulation of the centers and covariance matrices of
+// the Gaussians with respect to external parameters represented in the form of
+// candidate coordinate systems.
+//-----------------------------------------------------------------------------
+void train_EM_tensorGMM(const demonstration_list_t& demos,
+                        model_t &model) {
+
+    const int nb_max_steps = 100;			// Maximum number of iterations allowed
+    const int nb_min_steps = 5;				// Minimum number of iterations allowed
+    const double max_diff_log_likelihood = 1e-5;	// Likelihood increase threshold
+    // to stop the algorithm
+    const double diag_reg_fact = 1e-2;		// Regularization term is optional
+
+
+    cube data(model.nb_var, model.parameters.nb_frames,
+              demos.size() * model.parameters.nb_data);
+
+
+    for (int n = 0; n < demos.size(); ++n) {
+        for (int m = 0; m < model.parameters.nb_frames; ++m) {
+            data(span::all, span(m), span(n * model.parameters.nb_data,
+                                          (n + 1) * model.parameters.nb_data - 1)) =
+                    demos[n].points_in_coordinate_systems[m];
+        }
+    }
+
+
+    std::vector<double> log_likelihoods;
+
+    for (int iter = 0; iter < nb_max_steps; ++iter) {
+
+        // E-step
+        mat L = ones(model.parameters.nb_states, data.n_slices);
+
+        for (int i = 0; i < model.parameters.nb_states; ++i) {
+            for (int m = 0; m < model.parameters.nb_frames; ++m) {
+
+                // Matricization/flattening of tensor
+                mat data_mat(data(span::all, span(m), span::all));
+
+                vec gamma0 = gaussPDF(data_mat, model.mu[i][m], model.sigma[i][m]);
+
+                L(i, span::all) = L(i, span::all) % gamma0.t();
+            }
+
+            L(i, span::all) =  L(i, span::all) * model.priors(i);
+        }
+
+        mat gamma = L / repmat(sum(L, 0) + DBL_MIN, L.n_rows, 1);
+        mat gamma2 = gamma / repmat(sum(gamma, 1), 1, data.n_slices);
+
+        model.pix = gamma2;
+
+
+        // M-step
+        for (int i = 0; i < model.parameters.nb_states; ++i) {
+
+            // Update priors
+            model.priors(i) = sum(gamma(i, span::all)) / data.n_slices;
+
+            for (int m = 0; m < model.parameters.nb_frames; ++m) {
+
+                // Matricization/flattening of tensor
+                mat data_mat(data(span::all, span(m), span::all));
+
+                // Update mu
+                model.mu[i][m] = data_mat * gamma2(i, span::all).t();
+
+                // Update sigma
+                mat data_tmp = data_mat - repmat(model.mu[i][m], 1, data.n_slices);
+                model.sigma[i][m] = data_tmp * diagmat(gamma2(i, span::all)) * data_tmp.t() +
+                                    eye(data_tmp.n_rows, data_tmp.n_rows) * diag_reg_fact;
+            }
+        }
+
+        // Compute average log-likelihood
+        log_likelihoods.push_back(vec(sum(log(sum(L, 0)), 1))[0] / data.n_slices);
+
+        // Stop the algorithm if EM converged (small change of log-likelihood)
+        if (iter >= nb_min_steps) {
+            if (log_likelihoods[iter] - log_likelihoods[iter - 1] < max_diff_log_likelihood)
+                break;
+        }
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// Training of the model
+//-----------------------------------------------------------------------------
+void learn(const demonstration_list_t& demos, model_t &model) {
+
+    init_tensorGMM_kbins(demos, model);
+    train_EM_tensorGMM(demos, model);
+
+}
+
+
+/*************************** DEMONSTRATION SECTION ***************************/
+
+static void error_callback(int error, const char* description) {
+    fprintf(stderr, "Error %d: %s\n", error, description);
+}
+
+
+//-----------------------------------------------------------------------------
+// Contains all the informations about a viewport
+//-----------------------------------------------------------------------------
+struct viewport_t {
+    int x;
+    int y;
+    int width;
+    int height;
+
+    // Projection matrix parameters
+    arma::vec projection_top_left;
+    arma::vec projection_bottom_right;
+    double projection_near;
+    double projection_far;
+
+    // View matrix parameters
+    arma::fvec view;
+};
+
+
+//-----------------------------------------------------------------------------
+// Helper function to setup a viewport
+//-----------------------------------------------------------------------------
+void setup_viewport(viewport_t* viewport, int x, int y, int width, int height,
+                    double near = -1.0, double far = 1.0,
+                    const fvec& view_transforms = zeros<fvec>(3)) {
+
+    viewport->x = x;
+    viewport->y = y;
+    viewport->width = width;
+    viewport->height = height;
+    viewport->projection_top_left = vec({ (double) -width / 2,
+                                          (double) height / 2 });
+    viewport->projection_bottom_right = vec({ (double) width / 2,
+                                              (double) -height / 2 });
+    viewport->projection_near = near;
+    viewport->projection_far = far;
+    viewport->view = view_transforms;
+}
+
+
+//-----------------------------------------------------------------------------
+// Converts some coordinates from UI-space to OpenGL-space, taking the
+// coordinates of a viewport into account
+//-----------------------------------------------------------------------------
+arma::vec ui2fb(const arma::vec& coords, const gfx2::window_size_t& window_size,
+                const viewport_t& viewport) {
+    arma::vec result = coords;
+
+    // ui -> viewport
+    result(0) = coords(0) * (float) window_size.fb_width / (float) window_size.win_width - viewport.x;
+    result(1) = (window_size.win_height - coords(1)) *
+                (float) window_size.fb_height / (float) window_size.win_height - viewport.y;
+
+    // viewport -> fb
+    result(0) = result(0) - (float) viewport.width * 0.5f;
+    result(1) = result(1) - (float) viewport.height * 0.5f;
+
+    return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// Converts some coordinates from OpenGL-space to UI-space, taking the
+// coordinates of a viewport into account
+//-----------------------------------------------------------------------------
+arma::vec fb2ui(const arma::vec& coords, const gfx2::window_size_t& window_size,
+                const viewport_t& viewport) {
+    arma::vec result = coords;
+
+    // fb -> viewport
+    result(0) = result(0) + (float) viewport.width * 0.5f;
+    result(1) = result(1) + (float) viewport.height * 0.5f;
+
+    // viewport -> ui
+    result(0) = (result(0) + viewport.x) * (float) window_size.win_width /
+                (float) window_size.fb_width;
+
+    result(1) = window_size.win_height - (result(1) + viewport.y) *
+                                         (float) window_size.win_height / (float) window_size.fb_height;
+
+    return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// Colors used by the movable handlers
+//-----------------------------------------------------------------------------
+const arma::fmat HANDLER_COLORS({
+                                        { 0.0, 0.0,  0.0  },
+                                        { 0.0, 0.0,  1.0  },
+                                        { 0.0, 0.5,  0.0  },
+                                        { 1.0, 0.0,  0.0  },
+                                        { 0.0, 0.75, 0.75 },
+                                });
+
+
+//-----------------------------------------------------------------------------
+// Colors used by the fixed handlers
+//-----------------------------------------------------------------------------
+const arma::fmat HANDLER_FIXED_COLORS({
+                                              { 0.4, 0.4,  0.4  },
+                                              { 0.4, 0.4,  1.0  },
+                                              { 0.2, 0.5,  0.2  },
+                                              { 1.0, 0.4,  0.4  },
+                                              { 0.3, 0.75, 0.75 },
+                                      });
+
+
+//-----------------------------------------------------------------------------
+// Colors of the displayed lines and gaussians
+//-----------------------------------------------------------------------------
+const arma::mat COLORS({
+                               { 0.0,  0.0,  1.0  },
+                               { 0.0,  0.5,  0.0  },
+                               { 1.0,  0.0,  0.0  },
+                               { 0.0,  0.75, 0.75 },
+                               { 0.75, 0.0,  0.75 },
+                               { 0.75, 0.75, 0.0  },
+                               { 0.25, 0.25, 0.25 },
+                               { 0.0,  0.0,  1.0  },
+                               { 0.0,  0.5,  0.0  },
+                               { 1.0,  0.0,  0.0  },
+                       });
+
+
+//-----------------------------------------------------------------------------
+// An user-movable UI widget representing a coordinate system
+//
+// Can be "fixed", so the user can't move it anymore
+//-----------------------------------------------------------------------------
+class Handler
+{
+public:
+    Handler(const viewport_t* viewport, const ImVec2& position, const ImVec2& y,
+            int index)
+            : viewport(viewport), hovered(false), fixed(false), moved(false), index(index)
+    {
+        ui_position = position;
+        ui_y = y;
+
+        fvec color = HANDLER_COLORS.row(index).t();
+
+        models[0] = gfx2::create_rectangle(color, 25.0f, 5.0f);
+        models[0].transforms.parent = &transforms;
+        models[0].transforms.rotation = gfx2::rotate(arma::fvec({0.0f, 0.0f, 1.0f}),
+                                                     gfx2::deg2rad(90.0f));
+
+        models[1] = gfx2::create_rectangle(color, 60.0f, 5.0f);
+        models[1].transforms.parent = &transforms;
+        models[1].transforms.position(0) = 30.0f;
+        models[1].transforms.position(1) = -10.0f;
+
+        models[2] = gfx2::create_rectangle(color, 60.0f, 5.0f);
+        models[2].transforms.parent = &transforms;
+        models[2].transforms.position(0) = 30.0f;
+        models[2].transforms.position(1) = 10.0f;
+    }
+
+
+    void update(const gfx2::window_size_t& window_size)
+    {
+        transforms.position.rows(0, 1) = arma::conv_to<arma::fvec>::from(
+                ui2fb(ui_position, window_size, *viewport)
+        );
+
+        arma::vec delta = ui_y / arma::norm(arma::vec(ui_y));
+
+        transforms.rotation(0, 0) = -delta(0);
+        transforms.rotation(1, 0) = delta(1);
+        transforms.rotation(0, 1) = -delta(1);
+        transforms.rotation(1, 1) = -delta(0);
+    }
+
+
+    void update()
+    {
+        transforms.position(0) = ui_position.x;
+        transforms.position(1) = ui_position.y;
+
+        arma::vec delta = ui_y / arma::norm(arma::vec(ui_y));
+
+        transforms.rotation(0, 0) = -delta(0);
+        transforms.rotation(1, 0) = delta(1);
+        transforms.rotation(0, 1) = -delta(1);
+        transforms.rotation(1, 1) = -delta(0);
+    }
+
+
+    void viewport_resized(const gfx2::window_size_t& window_size)
+    {
+        ui_position = fb2ui(arma::conv_to<arma::vec>::from(transforms.position.rows(0, 1)),
+                            window_size, *viewport);
+    }
+
+
+    void fix()
+    {
+        fixed = true;
+
+        for (int i = 0; i < 3; ++i)
+            models[i].diffuse_color = HANDLER_FIXED_COLORS.row(index).t();
+    }
+
+
+    bool draw(const gfx2::window_size_t& window_size)
+    {
+        if (!fixed)
+        {
+            std::stringstream id;
+            id << "handler" << (uint64_t) this;
+
+            ImGuiWindow* window = ImGui::GetCurrentWindow();
+            if (window->SkipItems)
+                return false;
+
+            ImGui::PushID(id.str().c_str());
+
+            // Position
+            ImVec2 current_position = ui_position;
+
+            ui_position = ui::dragger(0, ui_position, false, ui::config.draggerSize );
+
+            moved = moved || (ui_position.x != current_position.x) || (ui_position.y != current_position.y);
+
+            hovered = ImGui::IsItemHovered();
+
+            // y-axis
+            ImVec2 py = ui_position + ui_y;
+            current_position = ui_y;
+
+            py = ui::dragger(1, py, false, ui::config.draggerSize * 0.7);
+            ui_y = py - ui_position;
+
+            moved = moved || ((ui_y.x != current_position.x) || (ui_y.y != current_position.y));
+
+            hovered = ImGui::IsItemHovered() || hovered;
+
+            window->DrawList->AddLine(ui_position, py, ui::config.lineColor);
+
+            ImGui::PopID();
+
+            update(window_size);
+        }
+
+        return hovered;
+    }
+
+
+    void draw_anchor() const
+    {
+        for (int i = 0; i < 3; ++i)
+            gfx2::draw(models[i]);
+    }
+
+
+public:
+    const viewport_t* viewport;
+    int index;
+
+    ImVec2 ui_position;
+    ImVec2 ui_y;
+
+    gfx2::transforms_t transforms;
+    gfx2::model_t models[3];
+
+    bool hovered;
+    bool fixed;
+    bool moved;
+};
+
+
+//-----------------------------------------------------------------------------
+// Represents a list of handlers
+//-----------------------------------------------------------------------------
+typedef std::vector<Handler*> handler_list_t;
+
+
+//-----------------------------------------------------------------------------
+// Contains all the needed infos about the state of the application (values of
+// the parameters modifiable via the UI, which action the user is currently
+// doing, ...)
+//-----------------------------------------------------------------------------
+struct gui_state_t {
+    // Indicates if the user can draw a new demonstration
+    bool can_draw_demonstration;
+
+    // Indicates if the user is currently drawing a new demonstration
+    bool is_drawing_demonstration;
+
+    // Indicates if the parameters dialog is displayed
+    bool is_parameters_dialog_displayed;
+
+    // Indicates if the parameters were modified through the UI
+    bool are_parameters_modified;
+
+    // Parameters modifiable via the UI (they correspond to the ones declared
+    //in parameters_t)
+    int parameter_nb_states;
+    int parameter_nb_frames;
+    int parameter_nb_data;
+
+    int parameter_nb_gmr_components;
+};
+
+
+//-----------------------------------------------------------------------------
+// Create a handler at a random position (within the given boundaries)
+//-----------------------------------------------------------------------------
+Handler* create_random_handler(const viewport_t* viewport, int index,
+                               int min_x, int min_y, int max_x, int max_y) {
+    return new Handler(viewport,
+                       ImVec2((randu() * 0.8f + 0.1f) * (max_x - min_x) + min_x,
+                              (randu() * 0.5f + 0.1f) * (max_y - min_y) + min_y),
+                       ImVec2((randu() - 0.5) * 10, randu() * -10 - 10),
+                       index);
+}
+
+
+//-----------------------------------------------------------------------------
+// Create handlers to be used for a new demonstration at random positions
+//-----------------------------------------------------------------------------
+void create_new_demonstration_handlers(const viewport_t& viewport,
+                                       const gfx2::window_size_t& window_size,
+                                       int nb_frames,
+                                       handler_list_t &handlers) {
+
+    for (size_t i = 0; i < handlers.size(); ++i)
+        delete handlers[i];
+
+    handlers.clear();
+
+    handlers.push_back(
+            new Handler(&viewport, ImVec2(window_size.win_width / 6,
+                                          window_size.win_height  - 50),
+                        ImVec2(0, 30), 0)
+    );
+
+    for (int n = 1; n < nb_frames; ++n) {
+        handlers.push_back(
+                create_random_handler(&viewport, n, 10, 20,
+                                      window_size.win_width / 3 - 10,
+                                      window_size.win_height / 2 - 20)
+        );
+    };
+}
+
+
+//-----------------------------------------------------------------------------
+// Create handlers to be used for a new reproduction at random positions
+//-----------------------------------------------------------------------------
+void create_reproduction_handlers(const viewport_t& viewport,
+                                  const gfx2::window_size_t& window_size,
+                                  int nb_frames,
+                                  handler_list_t &handlers) {
+
+    for (size_t i = 0; i < handlers.size(); ++i)
+        delete handlers[i];
+
+    handlers.clear();
+
+    handlers.push_back(
+            new Handler(&viewport, ImVec2(window_size.win_width / 2,
+                                          window_size.win_height - 50),
+                        ImVec2(0, 30), 0)
+    );
+
+    for (int n = 1; n < nb_frames; ++n) {
+        handlers.push_back(
+                create_random_handler(&viewport, n,
+                                      window_size.win_width / 3 + 20,
+                                      20,
+                                      window_size.win_width * 2 / 3 - 20,
+                                      window_size.win_height / 2- 20)
+        );
+    };
+}
+
+//-----------------------------------------------------------------------------
+// Create handlers to be used for moving GMR window
+//-----------------------------------------------------------------------------
+void create_reproduction_handlers_gmrmoving(const viewport_t& viewport,
+                                  const gfx2::window_size_t& window_size,
+                                  int nb_frames,
+                                  handler_list_t &handlers) {
+
+    for (size_t i = 0; i < handlers.size(); ++i)
+        delete handlers[i];
+
+    handlers.clear();
+
+    handlers.push_back(
+            new Handler(&viewport, ImVec2(window_size.win_width *5 / 6,
+                                          window_size.win_height - 50),
+                        ImVec2(0, 30), 0)
+    );
+
+    if (nb_frames > 1) {
+        for (int n = 1; n < nb_frames; ++n) {
+            handlers.push_back(
+                    create_random_handler(&viewport, n,
+                                          window_size.win_width * 2 / 3 + 20,
+                                          20,
+                                          window_size.win_width - 20,
+                                          window_size.win_height / 2 - 20)
+            );
+        };
+    };
+
+    for (int i = 0; i < handlers.size(); i++) {
+        handlers.at(i)->fix();
+        handlers.at(i)->update(window_size);
+    }
+
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Extract a list of coordinate systems from a list of handlers
+//-----------------------------------------------------------------------------
+void convert(const handler_list_t& from, coordinate_system_list_t &to,
+             const parameters_t& parameters) {
+
+    to.clear();
+
+    for (int n = 0; n < from.size(); ++n) {
+        to.push_back(
+                coordinate_system_t(arma::conv_to<arma::vec>::from(from[n]->transforms.position),
+                                    arma::conv_to<arma::mat>::from(from[n]->transforms.rotation),
+                                    parameters)
+        );
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// Extract a list of coordinate systems from a list of demonstrations
+//-----------------------------------------------------------------------------
+void convert(const demonstration_list_t& from, std::vector<coordinate_system_list_t> &to) {
+
+    to.clear();
+
+    for (int n = 0; n < from.size(); ++n) {
+        to.push_back(from[n].coordinate_systems);
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// Compute a view matrix centered on the given reference frame across all the
+// demonstrations
+//-----------------------------------------------------------------------------
+arma::fvec compute_centered_view_matrix(const demonstration_list_t& demonstrations,
+                                        int frame) {
+    vec top_left({-30, 0});
+    vec bottom_right({0, 0});
+
+    for (auto iter = demonstrations.begin(); iter != demonstrations.end(); ++iter) {
+        top_left(0) = fmin(top_left(0), iter->points_in_coordinate_systems[frame](0, span::all).min());
+        top_left(1) = fmax(top_left(1), iter->points_in_coordinate_systems[frame](1, span::all).max());
+
+        bottom_right(0) = fmax(bottom_right(0), iter->points_in_coordinate_systems[frame](0, span::all).max());
+        bottom_right(1) = fmin(bottom_right(1), iter->points_in_coordinate_systems[frame](1, span::all).min());
+    }
+
+    vec center = (bottom_right - top_left) / 2 + top_left;
+
+    return fvec({ (float) -center(0), (float) -center(1), 0.0f });
+}
+
+
+//-----------------------------------------------------------------------------
+// Render the "demonstrations" viewport
+//-----------------------------------------------------------------------------
+void draw_demos_viewport(const viewport_t& viewport,
+                         const std::vector<arma::vec>& current_trajectory,
+                         const demonstration_list_t& demonstrations,
+                         const std::vector<handler_list_t> fixed_demonstration_handlers,
+                         const handler_list_t current_demonstration_handlers) {
+
+    glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
+    glScissor(viewport.x, viewport.y, viewport.width, viewport.height);
+    glClearColor(0.7f, 0.7f, 0.7f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(viewport.projection_top_left(0), viewport.projection_bottom_right(0),
+            viewport.projection_bottom_right(1), viewport.projection_top_left(1),
+            viewport.projection_near, viewport.projection_far);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(viewport.view(0), viewport.view(1), viewport.view(2));
+
+    // Draw the currently created demonstration (if any)
+    if (current_trajectory.size() > 1) {
+        std::vector<arma::vec> tmpvec;
+        for (int i = 0; i < current_trajectory.size(); i++) {
+            tmpvec.push_back(current_trajectory.at(i).subvec(0, 1));
+        }
+        gfx2::draw_line(arma::fvec({0.33f, 0.97f, 0.33f}), tmpvec);
+        tmpvec.clear();
+    }
+
+    // Draw the demonstrations
+    int color_index = 0;
+    for (auto iter = demonstrations.begin(); iter != demonstrations.end(); ++iter) {
+        arma::mat datapoints = iter->points(span(0, 1), span::all);
+
+        arma::fvec color = arma::conv_to<arma::fvec>::from(COLORS.row(color_index));
+
+        gfx2::draw_line(color, datapoints);
+
+        ++color_index;
+        if (color_index >= demonstrations.size())
+            color_index = 0;
+    }
+
+    // Draw the handlers
+    for (size_t n = 0; n < fixed_demonstration_handlers.size(); ++n) {
+        for (size_t i = 0; i < fixed_demonstration_handlers[n].size(); ++i)
+            fixed_demonstration_handlers[n][i]->draw_anchor();
+    }
+
+    for (size_t i = 0; i < current_demonstration_handlers.size(); ++i)
+        current_demonstration_handlers[i]->draw_anchor();
+}
+
+
+//-----------------------------------------------------------------------------
+// Render a "reproduction" viewport
+//-----------------------------------------------------------------------------
+void draw_reproductions_viewport(const viewport_t& viewport,
+                                 const std::vector<handler_list_t>& handlers,
+                                 const matrix_list_t& reproductions) {
+
+    glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
+    glScissor(viewport.x, viewport.y, viewport.width, viewport.height);
+    glClearColor(0.9f, 0.9f, 0.9f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(viewport.projection_top_left(0), viewport.projection_bottom_right(0),
+            viewport.projection_bottom_right(1), viewport.projection_top_left(1),
+            viewport.projection_near, viewport.projection_far);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(viewport.view(0), viewport.view(1), viewport.view(2));
+
+    // Draw the handlers
+    for (size_t n = 0; n < handlers.size(); ++n) {
+        for (size_t i = 0; i < handlers[n].size(); ++i)
+            handlers[n][i]->draw_anchor();
+    }
+}
+
+
+//-----------------------------------------------------------------------------
+// Render a "reproduction" viewport
+//-----------------------------------------------------------------------------
+void draw_reproductions_viewport(const viewport_t& viewport,
+                                 const handler_list_t& handlers,
+                                 const matrix_list_t& reproductions) {
+
+    std::vector<handler_list_t> handler_list;
+    handler_list.push_back(handlers);
+
+    draw_reproductions_viewport(viewport, handler_list, reproductions);
+}
+
+
+//-----------------------------------------------------------------------------
+// Render a "GMMs" viewport
+//-----------------------------------------------------------------------------
+void draw_gmrmoving_viewport(const viewport_t& viewport,
+                        const handler_list_t& handlers, model_t model, int nb_gmr_components, int drawIndex) {
+
+    glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
+    glScissor(viewport.x, viewport.y, viewport.width, viewport.height);
+    glClearColor(0.9f, 0.9f, 0.9f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(viewport.projection_top_left(0), viewport.projection_bottom_right(0),
+            viewport.projection_bottom_right(1), viewport.projection_top_left(1),
+            viewport.projection_near, viewport.projection_far);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(viewport.view(0), viewport.view(1), viewport.view(2));
+
+
+    std::vector<handler_list_t> handler_list;
+    handler_list.push_back(handlers);
+
+    // Draw the handlers
+    for (size_t n = 0; n < handler_list.size(); ++n) {
+        for (size_t i = 0; i < handler_list[n].size(); ++i)
+            handler_list[n][i]->draw_anchor();
+    }
+
+    mat grey = {0.9, 0.9, 0.9};
+    mat black = {0.0, 0.0, 0.0};
+
+    if (model.mu.size() > 0) {
+        mat inputs = linspace(0, 199, nb_gmr_components);
+        inputs = inputs.t();
+        mat H(model.parameters.nb_states, inputs.size());
+
+        cube muGMR(2 * model.parameters.nb_deriv, inputs.size(), model.parameters.nb_frames);
+        muGMR = zeros(2 * model.parameters.nb_deriv, inputs.size(), model.parameters.nb_frames);
+        field<cube> sigmaGMR(model.parameters.nb_frames);
+
+        for (int i = 0; i < model.parameters.nb_frames; i++) {
+            sigmaGMR(i).set_size(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv, inputs.size());
+            sigmaGMR(i) = zeros(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv, inputs.size());
+        }
+
+        for (int m = 0; m < model.parameters.nb_frames; m++) {
+            for (int i = 0; i < model.parameters.nb_states; i++) {
+                H.row(i) = model.priors(i) * gaussPDF(inputs, model.mu[i][m].row(model.nb_var - 1),
+                                                      model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)).t();
+            }
+            H = H / repmat(sum(H + 1e-300), model.parameters.nb_states, 1);
+
+            mat muTmp(2 * model.parameters.nb_deriv, model.parameters.nb_states);
+            mat sigmaTmp;
+
+            for (int t = 0; t < inputs.size(); t++) {
+                // Compute conditional means
+                for (int i = 0; i < model.parameters.nb_states; i++) {
+                    muTmp.col(i) = model.mu[i][m].subvec(0, 2 * model.parameters.nb_deriv - 1) +
+                                   model.sigma[i][m].col(2 * model.parameters.nb_deriv).rows(0, 2 *
+                                                                                                model.parameters.nb_deriv -
+                                                                                                1) *
+                                   inv(model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)) *
+                                   (inputs(t) - model.mu[i][m].row(model.nb_var - 1));
+                    muGMR.slice(m).col(t) += H(i, t) * muTmp.col(i);
+                }
+
+                // Compute conditional covariances
+                for (int i = 0; i < model.parameters.nb_states; i++) {
+                    sigmaTmp = model.sigma[i][m].submat(0, 0, model.nb_var - 2, model.nb_var - 2) -
+                               model.sigma[i][m].col(2 * model.parameters.nb_deriv).rows(0,
+                                                                                         2 * model.parameters.nb_deriv -
+                                                                                         1) *
+                               inv(model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)) *
+                               model.sigma[i][m].row(2 * model.parameters.nb_deriv).cols(0,
+                                                                                         2 * model.parameters.nb_deriv -
+                                                                                         1);
+                    sigmaGMR(m).slice(t) += H(i, t) * (sigmaTmp + muTmp.col(i) * muTmp.col(i).t());
+                }
+
+                sigmaGMR(m).slice(t) += -muGMR.slice(m).col(t) * muGMR.slice(m).col(t).t() +
+                                        eye(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv) * 1e-4;
+            }
+        }
+
+        // transform mu/sigma GMR components into coordinate systems
+                cube muGMRt = zeros(2, inputs.size(), model.parameters.nb_frames);
+                field<cube> sigmaGMRt(model.parameters.nb_frames);
+                for (int i = 0; i < model.parameters.nb_frames; i++) {
+                    sigmaGMRt(i).resize(2, 2, inputs.size());
+                    sigmaGMRt(i) = zeros(2, 2, inputs.size());
+                }
+
+                for (int f = 0; f < model.parameters.nb_frames; f++) {
+                    muGMRt.slice(f) = handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1) * muGMR.slice(f).rows(0, 1);
+                    //muGMRt.slice(f).each_col() += handler_list[0][f]->transforms.position.subvec(0, 1);
+                    vec b = {handler_list[0][f]->transforms.position(0), handler_list[0][f]->transforms.position(1)};
+                    muGMRt.slice(f).each_col() += b;
+//                    mat dummy = repmat(b , 1, inputs.n_cols);
+//                    muGMR.slice(f) +=  tmpmat;
+                    for (int t = 0; t < inputs.size(); t++ ) {
+                        sigmaGMRt(f).slice(t) = handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1) *
+                                                            sigmaGMR(f).slice(t).submat(0, 0, 1, 1) *
+                                     handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1).t();
+                    }
+                }
+
+
+
+        // product
+        vec maxMuP = zeros(2, 1);
+        mat maxSigmaP = eye(2, 2);
+        for (int t = 0; t < inputs.size(); t++) {
+            vec muP = zeros(2, 1);
+            mat sigmaP = zeros(2, 2);
+
+            for (int m = 0; m < model.parameters.nb_frames; m++) {
+
+                sigmaP += inv(sigmaGMRt(m).slice(t) + eye(2, 2) * 1e-4);
+                muP += inv(sigmaGMRt(m).slice(t) + eye(2, 2) * 1e-4) * muGMRt.slice(m).col(t);
+            }
+
+            sigmaP = inv(sigmaP);
+            muP = sigmaP * muP;
+
+
+            if (t == drawIndex) {
+               maxMuP = muP;
+               maxSigmaP = sigmaP;
+            }
+
+
+            glClear(GL_DEPTH_BUFFER_BIT);
+            gfx2::draw_gaussian(conv_to<fvec>::from(grey.row(0).t()), muP, sigmaP);
+        }
+
+        glClear(GL_DEPTH_BUFFER_BIT);
+        gfx2::draw_gaussian(conv_to<fvec>::from(black.row(0).t()), maxMuP, maxSigmaP);
+
+    }
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Render a "Product" viewport
+//-----------------------------------------------------------------------------
+void draw_gmr_viewport(const viewport_t& viewport,
+                           const handler_list_t& handlers, model_t model, int nb_gmr_components, vec mouse, int &drawIndex) {
+
+    glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
+    glScissor(viewport.x, viewport.y, viewport.width, viewport.height);
+    glClearColor(0.9f, 0.9f, 0.9f, 0.0f);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(viewport.projection_top_left(0), viewport.projection_bottom_right(0),
+            viewport.projection_bottom_right(1), viewport.projection_top_left(1),
+            viewport.projection_near, viewport.projection_far);
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(viewport.view(0), viewport.view(1), viewport.view(2));
+
+
+    std::vector<handler_list_t> handler_list;
+    handler_list.push_back(handlers);
+
+    // Draw the handlers
+    for (size_t n = 0; n < handler_list.size(); ++n) {
+        for (size_t i = 0; i < handler_list[n].size(); ++i)
+            handler_list[n][i]->draw_anchor();
+    }
+
+    mat grey = {0.9, 0.9, 0.9};
+    mat black = {0.0, 0.0, 0.0};
+
+    // Draw the Product GMM states
+
+    // GMR
+    //int numGauss = 20; // later load it from GUI
+    if (model.mu.size() > 0) {
+        mat inputs = linspace(0, 199, nb_gmr_components);
+        inputs = inputs.t();
+        mat H(model.parameters.nb_states, inputs.size());
+
+        cube muGMR(2 * model.parameters.nb_deriv, inputs.size(), model.parameters.nb_frames);
+        muGMR = zeros(2 * model.parameters.nb_deriv, inputs.size(), model.parameters.nb_frames);
+        field<cube> sigmaGMR(model.parameters.nb_frames);
+
+        for (int i = 0; i < model.parameters.nb_frames; i++) {
+            sigmaGMR(i).set_size(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv, inputs.size());
+            sigmaGMR(i) = zeros(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv, inputs.size());
+        }
+
+        for (int m = 0; m < model.parameters.nb_frames; m++) {
+            for (int i = 0; i < model.parameters.nb_states; i++) {
+                H.row(i) = model.priors(i) * gaussPDF(inputs, model.mu[i][m].row(model.nb_var - 1),
+                                                      model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)).t();
+            }
+            H = H / repmat(sum(H + 1e-300), model.parameters.nb_states, 1);
+
+            mat muTmp(2 * model.parameters.nb_deriv, model.parameters.nb_states);
+            mat sigmaTmp;
+
+            for (int t = 0; t < inputs.size(); t++) {
+                // Compute conditional means
+                for (int i = 0; i < model.parameters.nb_states; i++) {
+                    muTmp.col(i) = model.mu[i][m].subvec(0, 2 * model.parameters.nb_deriv - 1) +
+                                   model.sigma[i][m].col(2 * model.parameters.nb_deriv).rows(0, 2 *
+                                                                                                model.parameters.nb_deriv -
+                                                                                                1) *
+                                   inv(model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)) *
+                                   (inputs(t) - model.mu[i][m].row(model.nb_var - 1));
+                    muGMR.slice(m).col(t) += H(i, t) * muTmp.col(i);
+                }
+
+                // Compute conditional covariances
+                for (int i = 0; i < model.parameters.nb_states; i++) {
+                    sigmaTmp = model.sigma[i][m].submat(0, 0, model.nb_var - 2, model.nb_var - 2) -
+                               model.sigma[i][m].col(2 * model.parameters.nb_deriv).rows(0,
+                                                                                         2 * model.parameters.nb_deriv -
+                                                                                         1) *
+                               inv(model.sigma[i][m].row(model.nb_var - 1).col(model.nb_var - 1)) *
+                               model.sigma[i][m].row(2 * model.parameters.nb_deriv).cols(0,
+                                                                                         2 * model.parameters.nb_deriv -
+                                                                                         1);
+                    sigmaGMR(m).slice(t) += H(i, t) * (sigmaTmp + muTmp.col(i) * muTmp.col(i).t());
+                }
+
+                sigmaGMR(m).slice(t) += -muGMR.slice(m).col(t) * muGMR.slice(m).col(t).t() +
+                                        eye(2 * model.parameters.nb_deriv, 2 * model.parameters.nb_deriv) * 1e-4;
+            }
+        }
+
+        // transform mu/sigma GMR components into coordinate systems
+                cube muGMRt = zeros(2, inputs.size(), model.parameters.nb_frames);
+                field<cube> sigmaGMRt(model.parameters.nb_frames);
+                for (int i = 0; i < model.parameters.nb_frames; i++) {
+                    sigmaGMRt(i).resize(2, 2, inputs.size());
+                    sigmaGMRt(i) = zeros(2, 2, inputs.size());
+                }
+
+                for (int f = 0; f < model.parameters.nb_frames; f++) {
+                    muGMRt.slice(f) = handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1) * muGMR.slice(f).rows(0, 1);
+                    //muGMRt.slice(f).each_col() += handler_list[0][f]->transforms.position.subvec(0, 1);
+                    vec b = {handler_list[0][f]->transforms.position(0), handler_list[0][f]->transforms.position(1)};
+                    muGMRt.slice(f).each_col() += b;
+//                    mat dummy = repmat(b , 1, inputs.n_cols);
+//                    muGMR.slice(f) +=  tmpmat;
+                    for (int t = 0; t < inputs.size(); t++ ) {
+                        sigmaGMRt(f).slice(t) = handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1) *
+                                                            sigmaGMR(f).slice(t).submat(0, 0, 1, 1) *
+                                     handler_list[0][f]->transforms.rotation.submat(0, 0, 1, 1).t();
+                    }
+                }
+
+
+
+        // product
+        double maxLL = 0.0;
+        vec LLs = zeros(inputs.size(), 1);
+        vec maxMuP = zeros(2, 1);
+        mat maxSigmaP = eye(2, 2);
+        for (int t = 0; t < inputs.size(); t++) {
+            vec muP = zeros(2, 1);
+            mat sigmaP = zeros(2, 2);
+
+            for (int m = 0; m < model.parameters.nb_frames; m++) {
+
+                sigmaP += inv(sigmaGMRt(m).slice(t) + eye(2, 2) * 1e-4);
+                muP += inv(sigmaGMRt(m).slice(t) + eye(2, 2) * 1e-4) * muGMRt.slice(m).col(t);
+            }
+
+            sigmaP = inv(sigmaP);
+            muP = sigmaP * muP;
+
+            vec currLL = gaussPDF(mouse, muP, sigmaP);
+            LLs.at(t) = currLL(0);
+
+            if (LLs.at(t) >= maxLL) {
+               maxMuP = muP;
+               maxSigmaP = sigmaP;
+               maxLL =LLs.at(t);
+               drawIndex = t;
+            }
+
+
+            glClear(GL_DEPTH_BUFFER_BIT);
+            gfx2::draw_gaussian(conv_to<fvec>::from(grey.row(0).t()), muP, sigmaP);
+        }
+
+        glClear(GL_DEPTH_BUFFER_BIT);
+        gfx2::draw_gaussian(conv_to<fvec>::from(black.row(0).t()), maxMuP, maxSigmaP);
+
+    }
+
+
+}
+
+
+/******************************* MAIN FUNCTION *******************************/
+
+int main(int argc, char **argv) {
+    arma_rng::set_seed_random();
+
+    // Model
+    model_t model;
+
+    // Parameters
+    model.parameters.nb_states	= 4;
+    model.parameters.nb_frames	= 2;
+    model.parameters.nb_deriv	= 2;
+    model.parameters.nb_data	= 200;
+    model.parameters.dt			= 0.1f;
+
+    // Take 4k screens into account (framebuffer size != window size)
+    gfx2::window_size_t window_size;
+    window_size.win_width = 1200;
+    window_size.win_height = 400;
+    window_size.fb_width = -1;	// Will be known later
+    window_size.fb_height = -1;
+    int viewport_width = 0;
+    int viewport_height = 0;
+
+
+    // Initialise GLFW
+    glfwSetErrorCallback(error_callback);
+
+    if (!glfwInit())
+        return -1;
+
+    glfwWindowHint(GLFW_SAMPLES, 4);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
+    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
+
+    // Open a window and create its OpenGL context
+    GLFWwindow* window = create_window_at_optimal_size(
+            "Demo - TPGMR",
+            window_size.win_width, window_size.win_height
+    );
+
+    glfwMakeContextCurrent(window);
+
+    // Setup GLSL
+    gfx2::init();
+    glEnable(GL_SCISSOR_TEST);
+    glEnable(GL_DEPTH_TEST);
+    glEnable(GL_CULL_FACE);
+    glEnable(GL_LINE_SMOOTH);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    // Setup ImGui
+    ImGui::CreateContext();
+    ImGui_ImplGlfwGL2_Init(window, true);
+
+
+    // Viewports
+    viewport_t viewport_demos;
+    viewport_t viewport_gmr;
+    viewport_t viewport_gmrmoving;
+
+    // GUI state
+    gui_state_t gui_state;
+    gui_state.can_draw_demonstration = false;
+    gui_state.is_drawing_demonstration = false;
+    gui_state.is_parameters_dialog_displayed = false;
+    gui_state.are_parameters_modified = false;
+    gui_state.parameter_nb_data = model.parameters.nb_data;
+    gui_state.parameter_nb_states = model.parameters.nb_states;
+    gui_state.parameter_nb_frames = model.parameters.nb_frames;
+    gui_state.parameter_nb_gmr_components = 20;
+    std::chrono::microseconds ms2 = std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch());
+    long startTimeMsec = ms2.count();
+    ImVec2 initFramePos;
+    int drawIndex = 0;
+    bool reset_moving_handler = true;
+
+
+    // Initial handlers
+    std::vector<handler_list_t> fixed_demonstration_handlers;
+    handler_list_t current_demonstration_handlers;
+    handler_list_t reproduction_handlers;
+    handler_list_t reproduction_handlers_moving;
+
+    // create_new_demonstration_handlers(viewport_demos, window_size,
+    // 								  model.parameters.nb_frames,
+    // 								  current_demonstration_handlers
+    // );
+    //
+
+
+    // List of demonstrations and reproductions
+    demonstration_list_t demos;
+
+    // Main loop
+    std::vector<arma::vec> current_trajectory;
+
+    while (!glfwWindowShouldClose(window)) {
+        glfwPollEvents();
+
+        // Detect when the window was resized
+        if ((ImGui::GetIO().DisplaySize.x != window_size.win_width) ||
+            (ImGui::GetIO().DisplaySize.y != window_size.win_height)) {
+
+            bool first = (window_size.win_width == -1) || (window_size.fb_width == -1);
+
+            window_size.win_width = ImGui::GetIO().DisplaySize.x;
+            window_size.win_height = ImGui::GetIO().DisplaySize.y;
+
+            glfwGetFramebufferSize(window, &window_size.fb_width, &window_size.fb_height);
+
+            viewport_width = window_size.fb_width / 3 - 1;
+            viewport_height = window_size.fb_height;
+
+            // Update all the viewports
+            setup_viewport(&viewport_demos, 0, window_size.fb_height - viewport_height,
+                           viewport_width, viewport_height);
+
+            setup_viewport(&viewport_gmr, viewport_width + 2,
+                           window_size.fb_height - viewport_height,
+                           viewport_width, viewport_height);
+
+            setup_viewport(&viewport_gmrmoving, window_size.fb_width - viewport_width,
+                           window_size.fb_height - viewport_height,
+                           viewport_width, viewport_height);
+
+
+            // Update all the handlers
+            if (!first) {
+                for (size_t i = 0; i < current_demonstration_handlers.size(); ++i)
+                    current_demonstration_handlers[i]->viewport_resized(window_size);
+
+                for (size_t i = 0; i < reproduction_handlers.size(); ++i)
+                    reproduction_handlers[i]->viewport_resized(window_size);
+
+                for (size_t i = 0; i < reproduction_handlers_moving.size(); ++i)
+                    reproduction_handlers_moving[i]->viewport_resized(window_size);
+            }
+
+                // At the very first frame: load initial data from files (can't be done
+                // outside the loop because we need to know the size of the OpenGL front
+                // buffer)
+                //
+                // Note: The loaded data was recorded in another demo with 3x2 viewports,
+                // so appropriate scaling must be applied
+            else if ((window_size.win_width != -1) && (window_size.fb_width != -1)) {
+
+                cube loaded_trajectories;
+                mat loaded_frames;
+                //loaded_trajectories.load("data/data_tpgmm_product_trajectories.txt");
+                //loaded_frames.load("data/data_tpgmm_product_frames.txt");
+                loaded_trajectories.load("data/data_tpgmr_trajectories.txt");
+                loaded_frames.load("data/data_tpgmr_frames.txt");
+
+                // adding time as 3rd dimension
+                cube loaded_trajectories_tmp(loaded_trajectories.n_rows + 1, loaded_trajectories.n_cols, loaded_trajectories.n_slices);
+                for (int i = 0; i < loaded_trajectories.n_slices; i++) {
+                    vec tmpvec = linspace(0, loaded_trajectories.n_cols-1, loaded_trajectories.n_cols);
+                    loaded_trajectories_tmp.slice(i) = join_vert(loaded_trajectories.slice(i), tmpvec.t());
+                }
+                loaded_trajectories.resize(loaded_trajectories.n_rows + 1, loaded_trajectories.n_cols, loaded_trajectories.n_slices);
+                loaded_trajectories = loaded_trajectories_tmp;
+
+                for (int n = 0; n < loaded_frames.n_cols / 2; ++n) {
+                    Handler* handler1 = new Handler(
+                            &viewport_demos,
+                            ImVec2(loaded_frames(0, n * 2) * window_size.win_width,
+                                   loaded_frames(1, n * 2) * window_size.win_height * 2),
+                            ImVec2(loaded_frames(2, n * 2) * window_size.win_width,
+                                   loaded_frames(3, n * 2) * window_size.win_height * 2),
+                            0
+                    );
+                    handler1->update(window_size);
+                    handler1->fix();
+
+                    Handler* handler2 = new Handler(
+                            &viewport_demos,
+                            ImVec2(loaded_frames(0, n * 2 + 1) * window_size.win_width,
+                                   loaded_frames(1, n * 2 + 1) * window_size.win_height * 2),
+                            ImVec2(loaded_frames(2, n * 2 + 1) * window_size.win_width,
+                                   loaded_frames(3, n * 2 + 1) * window_size.win_height * 2),
+                            1
+                    );
+                    handler2->update(window_size);
+                    handler2->fix();
+
+                    handler_list_t handlers;
+                    handlers.push_back(handler1);
+                    handlers.push_back(handler2);
+
+                    fixed_demonstration_handlers.push_back(handlers);
+                }
+
+                Handler* handler_reproduction_1 = new Handler(
+                        &viewport_gmr,
+                        fixed_demonstration_handlers[0][0]->ui_position +
+                        ImVec2(window_size.win_width / 3, 0),
+                        fixed_demonstration_handlers[0][0]->ui_y,
+                        0
+                );
+                handler_reproduction_1->update(window_size);
+                reproduction_handlers.push_back(handler_reproduction_1);
+
+                Handler* handler_reproduction_2 = new Handler(
+                        &viewport_gmr,
+                        fixed_demonstration_handlers[0][1]->ui_position +
+                        ImVec2(window_size.win_width / 3, 0),
+                        fixed_demonstration_handlers[0][1]->ui_y,
+                        1
+                );
+                handler_reproduction_2->update(window_size);
+                reproduction_handlers.push_back(handler_reproduction_2);
+
+
+                // moving frames
+               Handler* handler_reproduction_moving1 = new Handler(
+                        &viewport_gmrmoving,
+                        fixed_demonstration_handlers[0][0]->ui_position +
+                        ImVec2(window_size.win_width * 2 / 3, 0),
+                        fixed_demonstration_handlers[0][0]->ui_y,
+                        0
+                );
+                handler_reproduction_moving1->fix();
+                handler_reproduction_moving1->update(window_size);
+                reproduction_handlers_moving.push_back(handler_reproduction_moving1);
+
+                Handler* handler_reproduction_moving2 = new Handler(
+                        &viewport_gmrmoving,
+                        fixed_demonstration_handlers[0][1]->ui_position +
+                        ImVec2(window_size.win_width * 2 / 3, 0),
+                        fixed_demonstration_handlers[0][1]->ui_y,
+                        1
+                );
+                handler_reproduction_moving2->fix();
+                handler_reproduction_moving2->update(window_size);
+                reproduction_handlers_moving.push_back(handler_reproduction_moving2);
+
+
+                for (int n = 0; n < loaded_trajectories.n_slices; ++n) {
+                    vector_list_t trajectory;
+                    for (int i = 0; i < loaded_trajectories.n_cols; ++i) {
+                        mat t = loaded_trajectories(span::all, span(i), span(n));
+                        t(0, span::all) *= window_size.fb_width;
+                        t(1, span::all) *= window_size.fb_height * 2;
+                        trajectory.push_back(t);
+                    }
+
+                    coordinate_system_list_t coordinate_systems;
+                    convert(fixed_demonstration_handlers[n], coordinate_systems, model.parameters);
+
+                    Demonstration demonstration(coordinate_systems, trajectory, model.parameters);
+                    demos.push_back(demonstration);
+                }
+
+                // Initial learning from the loaded data
+                learn(demos, model);
+
+            }
+        }
+
+
+        // If the parameters changed, recompute
+        if (gui_state.are_parameters_modified) {
+
+            // If the number of frames changed, clear everything
+            if (model.parameters.nb_frames != gui_state.parameter_nb_frames) {
+                demos.clear();
+                model.mu.clear();
+                model.sigma.clear();
+
+                for (size_t i = 0; i < current_demonstration_handlers.size(); ++i)
+                    delete current_demonstration_handlers[i];
+
+                for (size_t n = 0; n < fixed_demonstration_handlers.size(); ++n) {
+                    for (size_t i = 0; i < fixed_demonstration_handlers[n].size(); ++i)
+                        delete fixed_demonstration_handlers[n][i];
+                }
+
+                for (size_t i = 0; i < reproduction_handlers.size(); ++i)
+                    delete reproduction_handlers[i];
+
+                for (size_t i = 0; i < reproduction_handlers_moving.size(); ++i)
+                    delete reproduction_handlers_moving[i];
+
+
+                current_demonstration_handlers.clear();
+                fixed_demonstration_handlers.clear();
+                reproduction_handlers.clear();
+                reproduction_handlers_moving.clear();
+
+
+                create_new_demonstration_handlers(viewport_demos, window_size,
+                                                  gui_state.parameter_nb_frames,
+                                                  current_demonstration_handlers
+                );
+
+                create_reproduction_handlers(viewport_gmr, window_size,
+                                             gui_state.parameter_nb_frames,
+                                             reproduction_handlers);
+
+
+                create_reproduction_handlers_gmrmoving(viewport_gmrmoving, window_size,
+                                             gui_state.parameter_nb_frames,
+                                             reproduction_handlers_moving);
+
+                model.parameters.nb_frames = gui_state.parameter_nb_frames;
+
+                gui_state.can_draw_demonstration = true;
+                reset_moving_handler = true;
+            }
+
+            // If the number of states changed, recompute the model
+            if (model.parameters.nb_states != gui_state.parameter_nb_states) {
+
+                model.parameters.nb_states = gui_state.parameter_nb_states;
+
+                for (auto iter = demos.begin(); iter != demos.end(); ++iter)
+                    iter->update(model.parameters);
+
+                if (!demos.empty()) {
+                    learn(demos, model);
+                }
+            }
+
+            gui_state.are_parameters_modified = false;
+        }
+
+
+        // Start the rendering
+        ImGui_ImplGlfwGL2_NewFrame();
+
+        glViewport(0, 0, window_size.fb_width, window_size.fb_height);
+        glScissor(0, 0, window_size.fb_width, window_size.fb_height);
+        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        draw_demos_viewport(viewport_demos, current_trajectory, demos,
+                            fixed_demonstration_handlers,
+                            current_demonstration_handlers);
+
+        double mouse_x, mouse_y;
+        glfwGetCursorPos(window, &mouse_x, &mouse_y);
+        vec mp = ui2fb({ mouse_x, mouse_y }, window_size, viewport_gmr);
+
+        draw_gmr_viewport(viewport_gmr, reproduction_handlers, model, gui_state.parameter_nb_gmr_components, mp, drawIndex);
+
+
+
+        if (reproduction_handlers.size() > 0) {
+            int moving_handler_ix;
+            if (model.parameters.nb_frames > 1) {
+                moving_handler_ix = 1;
+            } else {
+                moving_handler_ix = 0;
+            }
+
+
+            if ( reset_moving_handler) {
+                initFramePos.x = reproduction_handlers_moving.at(moving_handler_ix)->ui_position.x;
+                initFramePos.y = reproduction_handlers_moving.at(moving_handler_ix)->ui_position.y;
+                reset_moving_handler = false;
+            }
+            ImVec2 diff;
+            std::chrono::microseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >( std::chrono::system_clock::now().time_since_epoch());
+            long currTimeMsec = ms.count();
+            float phase =  (currTimeMsec-startTimeMsec)/1E6 ;
+            diff.x = 50.0 * sin(phase);
+            diff.y = 10.0 * sin(2 * phase);
+            reproduction_handlers_moving.at(moving_handler_ix)->ui_position = initFramePos + diff;
+            reproduction_handlers_moving.at(moving_handler_ix)->update(window_size);
+        }
+
+        draw_gmrmoving_viewport(viewport_gmrmoving, reproduction_handlers_moving, model, gui_state.parameter_nb_gmr_components, drawIndex);
+
+
+        // Draw the UI controls of the handlers
+        ui::begin("handlers");
+
+        bool hovering_ui = false;
+
+        for (size_t i = 0; i < reproduction_handlers.size(); ++i) {
+            hovering_ui = reproduction_handlers[i]->draw(window_size) || hovering_ui;
+        }
+
+
+        for (size_t i = 0; i < reproduction_handlers_moving.size(); ++i) {
+            hovering_ui = reproduction_handlers_moving[i]->draw(window_size) || hovering_ui;
+        }
+
+        for (size_t i = 0; i < current_demonstration_handlers.size(); ++i)
+            hovering_ui = current_demonstration_handlers[i]->draw(window_size) || hovering_ui;
+
+        ui::end();
+
+
+        // Window: Demonstrations
+        ImGui::SetNextWindowSize(ImVec2(window_size.win_width / 3, 36));
+        ImGui::SetNextWindowPos(ImVec2(0, 0));
+        ImGui::Begin("Demonstrations", NULL,
+                     ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings |
+                     ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
+                     ImGuiWindowFlags_NoTitleBar
+        );
+
+        ImGui::Text("Demonstrations      ");
+        ImGui::SameLine();
+
+        if (!gui_state.can_draw_demonstration) {
+            if (ImGui::Button("Add")) {
+                create_new_demonstration_handlers(viewport_demos, window_size,
+                                                  gui_state.parameter_nb_frames,
+                                                  current_demonstration_handlers
+                );
+
+                gui_state.can_draw_demonstration = true;
+            }
+        }
+
+        ImGui::SameLine();
+
+        if (ImGui::Button("Clear")) {
+            demos.clear();
+            model.mu.clear();
+            model.sigma.clear();
+
+            for (size_t i = 0; i < current_demonstration_handlers.size(); ++i)
+                delete current_demonstration_handlers[i];
+
+            for (size_t n = 0; n < fixed_demonstration_handlers.size(); ++n) {
+                for (size_t i = 0; i < fixed_demonstration_handlers[n].size(); ++i)
+                    delete fixed_demonstration_handlers[n][i];
+            }
+
+            current_demonstration_handlers.clear();
+            fixed_demonstration_handlers.clear();
+
+            create_new_demonstration_handlers(viewport_demos, window_size,
+                                              model.parameters.nb_frames,
+                                              current_demonstration_handlers
+            );
+
+            gui_state.can_draw_demonstration = true;
+        }
+
+        ImGui::SameLine();
+        ImGui::Text("    ");
+        ImGui::SameLine();
+
+        if (ImGui::Button("Parameters"))
+            gui_state.is_parameters_dialog_displayed = true;
+
+        ImGui::SameLine();
+        if (ImGui::Button("Save")) {
+            cube tmpTrajs(2, model.parameters.nb_data, fixed_demonstration_handlers.size());
+            mat tmpFrames(4, 2 * fixed_demonstration_handlers.size());
+
+            for (int i = 0; i < fixed_demonstration_handlers.size(); i++) {
+                tmpFrames(0, i * 2) = fixed_demonstration_handlers.at(i).at(0)->ui_position.x / window_size.win_width ;
+                tmpFrames(1, i * 2) =fixed_demonstration_handlers.at(i).at(0)->ui_position.y / window_size.win_height / 2;
+                tmpFrames(2, i * 2) =fixed_demonstration_handlers.at(i).at(0)->ui_y.x / window_size.win_width ;
+                tmpFrames(3, i * 2) =fixed_demonstration_handlers.at(i).at(0)->ui_y.y / window_size.win_height / 2;
+
+                tmpFrames(0, i*2 + 1) = fixed_demonstration_handlers.at(i).at(1)->ui_position.x / window_size.win_width;
+                tmpFrames(1, i*2 + 1) =fixed_demonstration_handlers.at(i).at(1)->ui_position.y / window_size.win_height / 2;
+                tmpFrames(2, i*2 + 1) =fixed_demonstration_handlers.at(i).at(1)->ui_y.x / window_size.win_width;
+                tmpFrames(3, i*2 + 1) =fixed_demonstration_handlers.at(i).at(1)->ui_y.y / window_size.win_height / 2;
+
+            }
+            tmpFrames.save("data/data_tpgmr_frames.txt", arma_ascii);
+
+            for (int i = 0; i < demos.size(); i++ ) {
+                tmpTrajs.slice(i).row(0) =  demos.at(i).points.row(0) / window_size.fb_width;
+                tmpTrajs.slice(i).row(1)  = demos.at(i).points.row(1) / window_size.fb_height / 2;
+            }
+
+            tmpTrajs.save("data/data_tpgmr_trajectories.txt", arma_ascii);
+
+        }
+
+        hovering_ui = ImGui::IsWindowHovered() || hovering_ui;
+
+
+
+        ImGui::End();
+
+        // Window: GMR
+        ImGui::SetNextWindowSize(ImVec2(window_size.win_width / 3, 36));
+        ImGui::SetNextWindowPos(ImVec2(window_size.win_width / 3, 0));
+        ImGui::Begin("TPGMR", NULL,
+                     ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings |
+                     ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
+                     ImGuiWindowFlags_NoTitleBar
+        );
+
+        ImGui::Text("TPGMR");
+        ImGui::SameLine();
+        ImGui::SliderInt("Nb components", &gui_state.parameter_nb_gmr_components, 10, 199);
+
+        hovering_ui = ImGui::IsWindowHovered() || hovering_ui;
+
+        ImGui::End();
+
+        // Window: GMMs in global coordinates
+        ImGui::SetNextWindowSize(ImVec2(window_size.win_width / 3, 36));
+        ImGui::SetNextWindowPos(ImVec2(window_size.win_width * 2 / 3, 0));
+        ImGui::Begin("GMMs", NULL,
+                     ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings |
+                     ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse |
+                     ImGuiWindowFlags_NoTitleBar
+        );
+
+        ImGui::Text("TPGMR (changing TPs)");
+        ImGui::SameLine();
+        if (ImGui::Button("Randomize")) {
+                for (size_t i = 0; i < reproduction_handlers_moving.size(); ++i)
+                    delete reproduction_handlers_moving[i];
+
+                reproduction_handlers_moving.clear();
+
+                create_reproduction_handlers_gmrmoving(viewport_gmrmoving, window_size,
+                                             gui_state.parameter_nb_frames,
+                                             reproduction_handlers_moving);
+
+                reset_moving_handler = true;
+
+        }
+
+        hovering_ui = ImGui::IsWindowHovered() || hovering_ui;
+
+        ImGui::End();
+
+
+        // Window: Parameters
+        ImGui::SetNextWindowSize(ImVec2(600, 100));
+        ImGui::SetNextWindowPos(ImVec2((window_size.win_width - 600) / 2, (window_size.win_height - 100) / 2));
+        ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 255));
+
+        if (gui_state.is_parameters_dialog_displayed)
+            ImGui::OpenPopup("Parameters");
+
+        if (ImGui::BeginPopupModal("Parameters", NULL,
+                                   ImGuiWindowFlags_NoResize |
+                                   ImGuiWindowFlags_NoSavedSettings)) {
+
+            ImGui::SliderInt("Nb states", &gui_state.parameter_nb_states, 1, 10);
+            ImGui::SliderInt("Nb frames", &gui_state.parameter_nb_frames, 1, 5);
+
+            if (ImGui::Button("Close")) {
+                ImGui::CloseCurrentPopup();
+                gui_state.is_parameters_dialog_displayed = false;
+                gui_state.are_parameters_modified = true;
+            }
+
+            ImGui::EndPopup();
+
+            hovering_ui = true;
+        }
+
+        ImGui::PopStyleColor();
+
+
+        // GUI rendering
+        ImGui::Render();
+        ImGui_ImplGlfwGL2_RenderDrawData(ImGui::GetDrawData());
+
+        // Swap buffers
+        glfwSwapBuffers(window);
+
+        // Keyboard input
+        if (ImGui::IsKeyPressed(GLFW_KEY_ESCAPE))
+            break;
+
+
+        // Left click: start a new demonstration (only if not on the UI and in the
+        // demonstrations viewport)
+        if (!gui_state.is_drawing_demonstration) {
+            if (ImGui::IsMouseClicked(GLFW_MOUSE_BUTTON_1) && gui_state.can_draw_demonstration) {
+                double mouse_x, mouse_y;
+                glfwGetCursorPos(window, &mouse_x, &mouse_y);
+
+                if (!hovering_ui && (mouse_x <= window_size.win_width / 3))
+                {
+                    gui_state.is_drawing_demonstration = true;
+
+                    vec coords = ui2fb({ mouse_x, mouse_y }, window_size, viewport_demos);
+                    vec tmpvec = {0.0};
+                    coords = join_vert(coords, tmpvec);
+
+                    current_trajectory.push_back(coords);
+                }
+            }
+        } else {
+            double mouse_x, mouse_y;
+            glfwGetCursorPos(window, &mouse_x, &mouse_y);
+
+            vec coords = ui2fb({ mouse_x, mouse_y }, window_size, viewport_demos);
+            vec tmpvec = {(float)current_trajectory.size() - 1};
+            coords = join_vert(coords, tmpvec);
+
+            vec last_point = current_trajectory[current_trajectory.size() - 1];
+            vec diff = abs(coords - last_point);
+
+            if ((diff(0) > 1e-6) && (diff(1) > 1e-6))
+                current_trajectory.push_back(coords);
+
+            // Left mouse button release: end the demonstration creation
+            if (!ImGui::IsMouseDown(GLFW_MOUSE_BUTTON_1)) {
+                gui_state.is_drawing_demonstration = false;
+
+                if (current_trajectory.size() > 1) {
+
+                    coordinate_system_list_t coordinate_systems;
+                    convert(current_demonstration_handlers, coordinate_systems, model.parameters);
+
+                    Demonstration demonstration(coordinate_systems, current_trajectory,
+                                                model.parameters);
+
+                    demos.push_back(demonstration);
+
+                    for (int i = 0; i < current_demonstration_handlers.size(); ++i)
+                        current_demonstration_handlers[i]->fix();
+
+                    fixed_demonstration_handlers.push_back(current_demonstration_handlers);
+                    current_demonstration_handlers.clear();
+
+                    learn(demos, model);
+
+                    gui_state.can_draw_demonstration = false;
+                }
+
+                current_trajectory.clear();
+            }
+        }
+
+        ImGui::CaptureMouseFromApp();
+    }
+
+
+    // Cleanup
+    ImGui_ImplGlfwGL2_Shutdown();
+    glfwTerminate();
+
+    return 0;
+}
+