Commit 9ad212ad by Fernando Martínez Santiago

Merge branch 'develop' of http://gitlab.ujaen.es/yotta/pictogram into develop

parents 9b6b3c0a 40d276f2
......@@ -78,7 +78,7 @@ public class Vocabulary implements Iterable<Picto> {
modifyAttsPicto(picto_cat, picto_id, args.getJSONObject("attributes"));
} catch (JSONException e) {
e.printStackTrace();
Log.e(LOG_TAG,e.getMessage());
Log.e(LOG_TAG,"Error updating picto:"+e.getMessage());
}
break;
}
......@@ -457,7 +457,7 @@ public class Vocabulary implements Iterable<Picto> {
});
} catch (Exception e) {
e.printStackTrace();
Log.e(Vocabulary.class.getCanonicalName(), e.getMessage());
Log.e(Vocabulary.class.getCanonicalName(), "Error saving picto:"+e.getMessage());
}
}
......
......@@ -102,10 +102,10 @@ public class PictoUploader {
boolean success;
Response<JsonObject> response=null;
String [] path = audioFile.getPath().split("\\.");
String extension = path[1];
if (extension != "mp3")
String extension = audioFile.getName().substring(audioFile.getName().lastIndexOf('.')+1);
if (!extension.equalsIgnoreCase("mp3"))
throw new UnsupportedEncodingException("Extension "+extension+" is not supported. Only mp3 files");
Ion ion = Ion.getDefault(PCBcontext.getContext());
......@@ -114,7 +114,7 @@ public class PictoUploader {
response=ion.with(PCBcontext.getContext())
.load("POST", PCBcontext.getContext().getResources().getString(R.string.server) + "/picto/upload_sound/"+picto.get_stupicto_id())
.setMultipartParameter("filename", "id_del _sonido")
.setMultipartParameter("filename", audioFile.getName())
.setMultipartParameter("extension", "mp3")
.setMultipartParameter("owner", Integer.toString(PCBcontext.getPcbdb().getCurrentUser().get_id_sup()))
.setMultipartParameter("folder", "pictoSound")
......@@ -138,7 +138,7 @@ public class PictoUploader {
success=false;
Log.i(LOG_TAG, "Uploaded Sound failed ");
if (response != null)
Log.i(LOG_TAG, "Uploaded Sound failed, headers: " + response.getHeaders());
Log.i(LOG_TAG, "Uploaded Sound failed, headers: " + response.getHeaders().message()+"("+response.getHeaders().code()+")");
}
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Sound upload error: " + e.getMessage()+ "Code: "+
......@@ -300,14 +300,15 @@ public class PictoUploader {
if (imgUpload_success){
if(this.picto.getUriSound() != "" && this.picto.getUriSound() != null ){ //Si el picto tiene audio en local
Log.i("TAG_PRUEBAS","Hay uri: "+this.picto.getUriSound()+" -Procede a subir archivo");
Log.i(LOG_TAG,"Uploading sound "+this.picto.getUriSound());
File file = new File(picto.getUriSound()); //Obtengo el fichero de audio local
boolean soundUpload_success = uploadSound(file); //Llamo a la subida
if(soundUpload_success) {
Log.i("TAG_PRUEBAS","Se sube sonido hay EXITO");
Log.i(LOG_TAG,"Sound uploaded");
}else {
GUITools.show_alert(PCBcontext.getActivityContext(),Integer.parseInt(R.string.upload_error+"Audio"), PictoUploader.this.picto.get_translation());
Log.e(LOG_TAG, "Uploading sound error");
GUITools.show_alert(PCBcontext.getActivityContext(),R.string.upload_error, PictoUploader.this.picto.get_translation());
}
}
if (stupicto_id!=Picto.STUPICTO_NULL) {
......
......@@ -26,6 +26,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
......@@ -38,7 +39,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.yottacode.pictogram.dao.Picto;
import com.yottacode.pictogram.dao.User;
import com.yottacode.pictogram.tabletlibrary.R;
import com.yottacode.pictogram.tabletlibrary.gui.communicator.BotonCircular;
import com.yottacode.pictogram.tabletlibrary.gui.communicator.PictoMenu;
......@@ -55,7 +55,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Random;
import java.util.Vector;
import pl.droidsonroids.gif.GifTextView;
......@@ -225,6 +224,7 @@ public class EditPictoActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
setContentView(R.layout.edit_picto_layout);
//Persmisos para grabar audio
......
/*
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE stu_picto DROP FOREIGN KEY stu_picto_scene_fk;
ALTER TABLE stu_picto DROP COLUMN id_scene;
ALTER TABLE stu_picto DROP id_scene;
DROP TABLE scene;
SET FOREIGN_KEY_CHECKS = 1;
*/
DELIMITER $$
......@@ -13,7 +14,8 @@ CREATE PROCEDURE scene_adapt()
BEGIN
DECLARE _id_stu INT;
DECLARE _id_sup INT;
DECLARE cat_active BOOLEAN;
DECLARE _cat_status CHAR(10);
DECLARE _cat_active BOOLEAN;
DECLARE done INT DEFAULT FALSE;
DECLARE LID INT;
......@@ -31,14 +33,19 @@ BEGIN
LEAVE read_loop;
END IF;
SELECT attributes->"$.categories" INTO cat_active FROM student WHERE id = _id_stu;
SET cat_active = 0;
SELECT CONCAT('active: ', cat_active);
SELECT CONCAT('active: ', NOT cat_active);
SELECT CAST(attributes->"$.categories" as CHAR(10)) INTO _cat_status FROM student WHERE id = _id_stu;
IF (_cat_status LIKE '%on%') THEN
SET _cat_active = 1;
/*SELECT CONCAT('active: ', _cat_active);*/
ELSE
SET _cat_active = 0;
/*SELECT CONCAT('active: ', NOT _cat_active);*/
END IF;
/* FIRST SCENE, ACTIVE, WITH CATEGORIES */
/* FIRST SCENE, ACTIVE, WITH CATEGORIES*/
INSERT INTO `scene` (name, active, categories, id_stu)
VALUES ('with_categories', cat_active, 1, _id_stu);
VALUES ('with_categories', _cat_active, 1, _id_stu);
SET LID = LAST_INSERT_ID();
......@@ -48,9 +55,9 @@ BEGIN
AND attributes->"$.free_category_coord_x" IS NULL
AND attributes->"$.free_category_coord_y" IS NULL;
/* SECOND SCENE, NOT ACTIVE, NO CATEGORIES */
/* SECOND SCENE, NOT ACTIVE, NO CATEGORIES*/
INSERT INTO `scene` (name, active, categories, id_sup, id_stu)
VALUES ('no_categories', NOT cat_active, 0, _id_sup, _id_stu);
VALUES ('no_categories', NOT _cat_active, 0, _id_sup, _id_stu);
SET LID = LAST_INSERT_ID();
......
......@@ -190,7 +190,7 @@ INSERT IGNORE INTO `student` (
NULL,
'es-es',
(SELECT id from office WHERE email='belen.perez@autismojaen.es'),
'{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
'{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
), (
'alumno2',
'$2a$10$RUv25u.C/waYE4xxbfTWTe/IBNQfIFFP5dKPTJsqYznbkS3QCvqq2',
......@@ -203,7 +203,7 @@ INSERT IGNORE INTO `student` (
NULL,
'es-es',
(SELECT id from office WHERE email='belen.perez@autismojaen.es'),
'{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
'{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
), (
'alumno3',
'$2a$10$Ei9E2Pz8sJ4aojbMPsdfZ.xz.LrWG4op1koC4LwCxHr.A0MgeP4m6',
......@@ -216,7 +216,7 @@ INSERT IGNORE INTO `student` (
NULL,
'es-es',
(SELECT id from office WHERE email='belen.perez@autismojaen.es'),
'{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
'{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
-- 'manuel',
-- '$2a$06$SaAswfsdqGpSo/bE.Cks8.CJnpqHGjixdRLGGpdOHWVFJR2w0fTaS',
......@@ -229,7 +229,7 @@ INSERT IGNORE INTO `student` (
-- NULL,
-- 'es-es',
-- (SELECT id from office WHERE email='belen.perez@autismojaen.es'),
-- '{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
-- '{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
-- ), (
-- 'jose',
-- '$2a$06$WtRXXLwFrEdDzB7r0r54RuY5A9wX3aysUIM8AHAGPpfVxhbNISBIa',
......@@ -242,7 +242,7 @@ INSERT IGNORE INTO `student` (
-- NULL,
-- 'es-es',
-- (SELECT id from office WHERE email='belen.perez@autismojaen.es'),
-- '{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
-- '{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
-- ), (
-- 'carmen',
-- '$2a$06$2c4zNE1Bkc24AXiXATbn8OfgkM/r9DJzUfnJ8qHrDUxBkMQd8rUIG',
......@@ -255,7 +255,7 @@ INSERT IGNORE INTO `student` (
-- NULL,
-- 'es-es',
-- (SELECT id from office WHERE email='belen.perez@autismojaen.es'),
-- '{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
-- '{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
);
--
......
......@@ -223,7 +223,7 @@ INSERT INTO `student` (
'test_caja_juan.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'faf0002',
'$2a$10$FOJ2fmJaHyI5sWe1tQojFuhoPpqHSTVPwvHPTpWEftFPI28VdyYNq',
......@@ -235,7 +235,7 @@ INSERT INTO `student` (
'test_caja_kate.jpg',
NULL,
'en-gb',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'mam0001',
'$2a$10$zygC/WviDviyZQsMsNqK8.tSUI4Qr/dLlLrw0i5kR1bbN4SeU5ACq',
......@@ -247,7 +247,7 @@ INSERT INTO `student` (
'test_caja_carlos.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'mam0002',
'$2a$10$xbyNUhf9rqhdXDBrvUSiOuJIzUVOyyz9ToQMCByFThiiiPwO0PWgK',
......@@ -259,7 +259,7 @@ INSERT INTO `student` (
'test_caja_rocio.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0001',
'$2a$10$koWKIn42UNSi1N67akxjpOuJNwpXJ/vOe6biD2xkjrUz6dr3g.Wa.',
......@@ -271,7 +271,7 @@ INSERT INTO `student` (
'test_caja_samuel.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "es" }'
), (
'aaa0002',
'$2a$10$ffAjZjWN0UKja0JO7ko6qup4x2phbY3VpC66TmpMnGdWUutBFeWY2',
......@@ -283,7 +283,7 @@ INSERT INTO `student` (
'test_caja_adela.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0003',
'$2a$10$glc5A6vyPve5.4407Vdkau5CHF3GOpA0Uo6rxMDdIopIWTJK0nBse',
......@@ -295,7 +295,7 @@ INSERT INTO `student` (
'test_caja_adela.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'aaa0004',
'$2a$10$tezK07jq5ZMdQbCboubEBeHiXWJisZPAbgN301n5kRLXkq8xOlb4O',
......@@ -307,7 +307,7 @@ INSERT INTO `student` (
'test_caja_juan.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'jaj0001',
'$2a$10$UQYGXOOE8mxxOjvgo8cjwOpsv5jCtRXpMTLpbD3TzMBiUIv3hXlnO',
......@@ -319,7 +319,7 @@ INSERT INTO `student` (
'test_caja_adela.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
), (
'jaj0002',
'$2a$10$tVy3Wfu35l4B6bFpnjJCE.ckjncq6YCKMGW4B9abesbiFVeyGu2Dy',
......@@ -331,7 +331,7 @@ INSERT INTO `student` (
'test_caja_samuel.jpg',
NULL,
'es-es',
'{"stu-att" : [{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }]}'
'{ "categories" : "on", "input feedback" : [ "vibration", "tts" ], "input selection" : "click", "pictogram size" : "medium", "tts engine" : "IVONA Text-to-Speech HQ", "tts voice": "en" }'
);
--
......
......@@ -74,7 +74,7 @@ INSERT IGNORE INTO `student` (
NULL,
'es-es',
(SELECT id from office WHERE email='centrodestrezas@gmail.com'),
'{"stu-att":[{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}]}'
'{"categories":"on","input feedback":["vibration","tts"],"input selection":"click","pictogram size":"medium"}'
);
INSERT IGNORE INTO `stu_picto` (
......
......@@ -58,6 +58,14 @@
target: "{{ server_path }}/{{ database_files_relative_path }}/test-{{ item }}.sql"
with_items: "{{ database_tests }}"
- name: Create scenes for existing stu_picto
mysql_db:
login_user: "{{ database_user }}"
login_password: "{{ database_user_passwd }}"
name: "{{ database_name }}"
state: import
target: "{{ server_path }}/{{ database_files_relative_path }}/scene_adapt.sql"
- name: Creates triggers
mysql_db:
login_user: "{{ database_user }}"
......
......@@ -44,14 +44,29 @@ module.exports = {
delete scene.categories;//To avoid update these fields
delete scene.supervisor;
delete scene.student;
scene.name = req.param('name') || instruction.name;
scene.active = req.param('active') || instruction.active;
scene.name = req.param('name') || scene.name;
scene.active = req.param('active') || scene.active;
scene.save(function (error) {
if (error) {
res.serverError();
} else {
res.ok(scene);
}
if(scene.active){
Student.findOne({id:scene.student})
.then(student => {
student.attributes.categories=scene.categories;
delete student.password;
student.save(function(error){
if(error){
res.serverError("Error saving student data");
}
else{
return res.ok(scene);
}
})
});
}
});
})
.catch(function () {
......@@ -100,6 +115,74 @@ module.exports = {
}).catch(function (err){
return res.serverError("Error finding scene "+err);
});
}
},
/**
* Copies a scene with its stu_pictos
* @param {request} req {} (id of source scene)
*/
duplicate: function(req,res){
Scene.findOne({id:req.params.id})
.populate('stuPictos').then(function(scene){
Scene.create({
name: scene.name,
active: false,
categories: scene.categories,
supervisor: scene.supervisor,
student: scene.student
}).then(scene=>{
async.forEach(scene.stuPictos, function (stuPicto, cb) {
StuPicto.create({
student: stuPicto.student,
picto: stuPicto.picto,
scene: scene.id,
attributes: stuPicto.attributes
}).catch(function (err){
console.log("Error creating stu_picto "+err.details);
sails.log.error(err.details);
});
},
function (err) { // function called when loop is done
if (err) {
console.log(err.details);
sails.log.error(err.details);
return res.json({
'error': err.details
});
} else
return res.ok(scene);
});
}).catch(function (err){
return res.serverError("Error creating scene: " + err);
});
});
},
//
// Logs a scene action and broadcast to anyone subscribed to this student
scene: function (req, res) {
var action = req.param('action');
var scene = req.param('scene');
var roomName = 'studentRoom' + scene.student;
if (req.isSocket) {
sails.log.debug("Inside scene - isSocket");
// Send to all sockets subscribed to this room except the own socket that sends the message
// Parameters: room, action, data to send, socket to avoid sending (the socket that send this)
sails.sockets.broadcast(roomName, 'scene', {
"action": action,
"scene": scene
}, req.socket);
res.json({
msg: "Action " + action + " in scene " + scene.id + " from student " + scene.student
});
}
},
};
......@@ -892,8 +892,9 @@ module.exports = {
/**
* Add an existing picto to the student's collection
* @param {request} req (with id_stu and id_picto as url parameters)
* @param {request} req (with id_scene,id_stu and id_picto as url parameters)
* {
* id_scene,
* id_stu,
* id_picto,
* attributes: { @see StuPicto.getValidAttributes() }
......@@ -928,7 +929,7 @@ module.exports = {
add_picto: function (req, res) {
var params = req.allParams();
StuPicto.find({id_pic: params.id_picto, id_stu: params.id_stu})
StuPicto.find({id_pic: params.id_picto, id_stu: params.id_stu, id_scene:params.id_scene})
.then((entries) => {
if (entries && entries.length > 0) {
var err = new Error("Picto already in student's vocabulary");
......
......@@ -147,6 +147,22 @@ module.exports = function eventsHook(sails) {
attributes: attributes
}
};
},
/**
* Scene is updated
* @param {action} type of the action
* @param {attributes} attributes of the action (id_stu, stu_picto)
* @return {Object} {name, data}
*/
scene: function (action, scene) {
return {
name: 'scene',
data: {
scene: scene,
action: action
}
};
}
};
};
......@@ -56,7 +56,6 @@ module.exports = {
pictos: function(id_scene, callback) {
var l = [];
var fs = require('fs');
console.log("metodo pictos scene");
Scene.findOne(id_scene)
.then((scene) => {
if (!scene)
......
......@@ -84,8 +84,10 @@ module.exports.policies = {
create: ['tokenAuth', 'isSupervisorOfStudent'],
update: ['tokenAuth', 'isSupervisorOfStudent'],
destroy: ['tokenAuth', 'isSupervisorOfStudent'],
duplicate: ['tokenAuth', 'isSupervisorOfStudent'],
getScene: ['tokenAuth'],
getStudentScenes: ['tokenAuth']
getStudentScenes: ['tokenAuth'],
scene: true
},
ServerController: {
......@@ -124,7 +126,8 @@ module.exports.policies = {
delete: ['tokenAuth', 'isSupAdmin'],
unlink_supervisor: ['tokenAuth', 'isSupAdmin'],
delete_picto: ['tokenAuth', 'isSupervisorOfStudent'],
getActiveScene: ['tokenAuth']
getActiveScene: ['tokenAuth'],
getScenes: ['tokenAuth']
},
LicenseController: {
......
......@@ -73,7 +73,11 @@ module.exports.routes = {
'DELETE /picto/:id': 'PictoController.destroy',
'DELETE /picto/:id_sup/tag/:id_tag': 'PictoController.del_tag',
/// Websocket request for propagating actions add, delete, modify...
'POST /scene': 'SceneController.scene',
'GET /scene/:id': 'SceneController.getScene',
'GET /scene/:id/copy': 'SceneController.duplicate',
'POST /scene/:id': 'SceneController.create',
'PUT /scene/:id': 'SceneController.update',
'DELETE /scene/:id': 'SceneController.destroy',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment