mirror of https://github.com/axmolengine/axmol.git
Merge branch 'v3' of https://github.com/cocos2d/cocos2d-x into v3_fix
This commit is contained in:
commit
c52132179a
3
AUTHORS
3
AUTHORS
|
@ -864,6 +864,9 @@ Developers:
|
||||||
favorcode
|
favorcode
|
||||||
Correct some doxygen comment
|
Correct some doxygen comment
|
||||||
|
|
||||||
|
asuuma
|
||||||
|
Fix Repeat will run one more over in rare situations.
|
||||||
|
|
||||||
Retired Core Developers:
|
Retired Core Developers:
|
||||||
WenSheng Yang
|
WenSheng Yang
|
||||||
Author of windows port, CCTextField,
|
Author of windows port, CCTextField,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
cocos2d-x-3.2 ???
|
cocos2d-x-3.2 ???
|
||||||
[NEW] TextureCache: added unbindImageAsync() and unbindAllImageAsync()
|
[NEW] TextureCache: added unbindImageAsync() and unbindAllImageAsync()
|
||||||
|
|
||||||
[FIX] Image: Set jpeg save quality to 90
|
|
||||||
[FIX] Application.mk: not output debug message in releae mode on Android
|
[FIX] Application.mk: not output debug message in releae mode on Android
|
||||||
|
[FIX] Image: Set jpeg save quality to 90
|
||||||
|
[FIX] Repeat: will run one more over in rare situations
|
||||||
|
|
||||||
cocos2d-x-3.1 May.24 2014
|
cocos2d-x-3.1 May.24 2014
|
||||||
[FIX] EventKeyboard::KeyCode: key code for back button changed from KEY_BACKSPACE to KEY_ESCAPE
|
[FIX] EventKeyboard::KeyCode: key code for back button changed from KEY_BACKSPACE to KEY_ESCAPE
|
||||||
|
|
|
@ -99,6 +99,7 @@ endif()
|
||||||
|
|
||||||
if(MINGW)
|
if(MINGW)
|
||||||
add_definitions(-DGLEW_STATIC)
|
add_definitions(-DGLEW_STATIC)
|
||||||
|
add_definitions(-D__SSIZE_T)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -439,7 +439,7 @@ void Repeat::update(float dt)
|
||||||
|
|
||||||
_innerAction->stop();
|
_innerAction->stop();
|
||||||
_innerAction->startWithTarget(_target);
|
_innerAction->startWithTarget(_target);
|
||||||
_nextDt += _innerAction->getDuration()/_duration;
|
_nextDt = _innerAction->getDuration()/_duration * (_total+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fix for issue #1288, incorrect end value of repeat
|
// fix for issue #1288, incorrect end value of repeat
|
||||||
|
|
|
@ -194,7 +194,7 @@ static const char* inet_ntop(int af, const void* src, char* dst, int cnt)
|
||||||
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
|
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
|
||||||
|
|
||||||
srcaddr.sin_family = af;
|
srcaddr.sin_family = af;
|
||||||
if (WSAAddressToString((struct sockaddr*) &srcaddr, sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt) != 0)
|
if (WSAAddressToStringA((struct sockaddr*) &srcaddr, sizeof(struct sockaddr_in), 0, dst, (LPDWORD) &cnt) != 0)
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,16 +44,11 @@ int ccNextPOT(int x)
|
||||||
return x + 1;
|
return x + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Utilities
|
namespace utils
|
||||||
{
|
{
|
||||||
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
|
/**
|
||||||
{
|
* Capture screen implementation, don't use it directly.
|
||||||
static CustomCommand captureScreenCommand;
|
*/
|
||||||
captureScreenCommand.init(std::numeric_limits<float>::max());
|
|
||||||
captureScreenCommand.func = std::bind(onCaptureScreen, afterCaptured, filename);
|
|
||||||
Director::getInstance()->getRenderer()->addCommand(&captureScreenCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onCaptureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
|
void onCaptureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
|
||||||
{
|
{
|
||||||
auto glView = Director::getInstance()->getOpenGLView();
|
auto glView = Director::getInstance()->getOpenGLView();
|
||||||
|
@ -112,6 +107,16 @@ void onCaptureScreen(const std::function<void(bool, const std::string&)>& afterC
|
||||||
afterCaptured(succeed, outputFile);
|
afterCaptured(succeed, outputFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* Capture screen interface
|
||||||
|
*/
|
||||||
|
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
|
||||||
|
{
|
||||||
|
static CustomCommand captureScreenCommand;
|
||||||
|
captureScreenCommand.init(std::numeric_limits<float>::max());
|
||||||
|
captureScreenCommand.func = std::bind(onCaptureScreen, afterCaptured, filename);
|
||||||
|
Director::getInstance()->getRenderer()->addCommand(&captureScreenCommand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_CC_END
|
NS_CC_END
|
||||||
|
|
|
@ -47,17 +47,17 @@ Examples:
|
||||||
|
|
||||||
int ccNextPOT(int value);
|
int ccNextPOT(int value);
|
||||||
|
|
||||||
namespace Utilities
|
namespace utils
|
||||||
{
|
{
|
||||||
/**
|
/** Capture the entire screen
|
||||||
* Capture screen interface
|
* To ensure the snapshot is applied after everything is updated and rendered in the current frame,
|
||||||
|
* we need to wrap the operation with a custom command which is then inserted into the tail of the render queue.
|
||||||
|
* @param afterCaptured, specify the callback function which will be invoked after the snapshot is done.
|
||||||
|
* @param filename, specify a filename where the snapshot is stored. This parameter can be either an absolute path or a simple
|
||||||
|
* base filename ("hello.png" etc.), don't use a relative path containing directory names.("mydir/hello.png" etc.)
|
||||||
|
* @since v3.2
|
||||||
*/
|
*/
|
||||||
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename);
|
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename);
|
||||||
|
|
||||||
/**
|
|
||||||
* The implementation of capturing screen
|
|
||||||
*/
|
|
||||||
void onCaptureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_CC_END
|
NS_CC_END
|
||||||
|
|
|
@ -52,6 +52,7 @@ ActionObject::~ActionObject()
|
||||||
{
|
{
|
||||||
_actionNodeList.clear();
|
_actionNodeList.clear();
|
||||||
CC_SAFE_RELEASE(_pScheduler);
|
CC_SAFE_RELEASE(_pScheduler);
|
||||||
|
CC_SAFE_RELEASE(_CallBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActionObject::setName(const char* name)
|
void ActionObject::setName(const char* name)
|
||||||
|
@ -166,6 +167,7 @@ void ActionObject::play(CallFunc* func)
|
||||||
{
|
{
|
||||||
this->play();
|
this->play();
|
||||||
this->_CallBack = func;
|
this->_CallBack = func;
|
||||||
|
CC_SAFE_RETAIN(_CallBack);
|
||||||
}
|
}
|
||||||
void ActionObject::pause()
|
void ActionObject::pause()
|
||||||
{
|
{
|
||||||
|
@ -214,6 +216,10 @@ void ActionObject::simulationActionUpdate(float dt)
|
||||||
{
|
{
|
||||||
this->play();
|
this->play();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pScheduler->unschedule(schedule_selector(ActionObject::simulationActionUpdate), this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,10 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"must_copy_resources": [
|
"must_copy_resources": [
|
||||||
|
{
|
||||||
|
"from": "../../../runtime/rtres",
|
||||||
|
"to": "rtres"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"from": "../../cocos2d-x/cocos/scripting/lua-bindings/script",
|
"from": "../../cocos2d-x/cocos/scripting/lua-bindings/script",
|
||||||
"to": ""
|
"to": ""
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version":"v3-lua-runtime-1.1.2",
|
"version":"v3-lua-runtime-1.1.3",
|
||||||
"zip_file_size":"21402175",
|
"zip_file_size":"21522933",
|
||||||
"repo_name":"cocos-runtime-bin",
|
"repo_name":"cocos-runtime-bin",
|
||||||
"repo_parent":"https://github.com/chukong/"
|
"repo_parent":"https://github.com/chukong/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,8 @@ static std::function<Layer*()> createFunctions[] = {
|
||||||
CL(Issue1288),
|
CL(Issue1288),
|
||||||
CL(Issue1288_2),
|
CL(Issue1288_2),
|
||||||
CL(Issue1327),
|
CL(Issue1327),
|
||||||
CL(Issue1398)
|
CL(Issue1398),
|
||||||
|
CL(Issue2599)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sceneIdx=-1;
|
static int sceneIdx=-1;
|
||||||
|
@ -2094,6 +2095,38 @@ std::string Issue1398::title() const
|
||||||
return "Issue 1398";
|
return "Issue 1398";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Issue2599::onEnter()
|
||||||
|
{
|
||||||
|
ActionsDemo::onEnter();
|
||||||
|
this->centerSprites(0);
|
||||||
|
|
||||||
|
_count = 0;
|
||||||
|
log("before: count = %d", _count);
|
||||||
|
|
||||||
|
log("start count up 50 times using Repeat action");
|
||||||
|
auto delay = 1.0f / 50;
|
||||||
|
auto repeatAction = Repeat::create(
|
||||||
|
Sequence::createWithTwoActions(
|
||||||
|
CallFunc::create([&](){ this->_count++; }),
|
||||||
|
DelayTime::create(delay)),
|
||||||
|
50);
|
||||||
|
this->runAction(
|
||||||
|
Sequence::createWithTwoActions(
|
||||||
|
repeatAction,
|
||||||
|
CallFunc::create([&]() { log("after: count = %d", this->_count); })
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Issue2599::subtitle() const
|
||||||
|
{
|
||||||
|
return "See console: You should see '50'";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Issue2599::title() const
|
||||||
|
{
|
||||||
|
return "Issue 2599";
|
||||||
|
}
|
||||||
|
|
||||||
/** ActionCatmullRom
|
/** ActionCatmullRom
|
||||||
*/
|
*/
|
||||||
void ActionCatmullRom::onEnter()
|
void ActionCatmullRom::onEnter()
|
||||||
|
|
|
@ -564,6 +564,18 @@ private:
|
||||||
int _testInteger;
|
int _testInteger;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Issue2599 : public ActionsDemo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CREATE_FUNC(Issue2599);
|
||||||
|
|
||||||
|
virtual void onEnter() override;
|
||||||
|
virtual std::string subtitle() const override;
|
||||||
|
virtual std::string title() const override;
|
||||||
|
private:
|
||||||
|
int _count;
|
||||||
|
};
|
||||||
|
|
||||||
class ActionCatmullRom : public ActionsDemo
|
class ActionCatmullRom : public ActionsDemo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -609,7 +609,7 @@ void CaptureScreenTest::onCaptured(Ref*)
|
||||||
Director::getInstance()->getTextureCache()->removeTextureForKey(_filename);
|
Director::getInstance()->getTextureCache()->removeTextureForKey(_filename);
|
||||||
removeChildByTag(childTag);
|
removeChildByTag(childTag);
|
||||||
_filename = "CaptureScreenTest.png";
|
_filename = "CaptureScreenTest.png";
|
||||||
Utilities::captureScreen(CC_CALLBACK_2(CaptureScreenTest::afterCaptured, this), _filename);
|
utils::captureScreen(CC_CALLBACK_2(CaptureScreenTest::afterCaptured, this), _filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CaptureScreenTest::afterCaptured(bool succeed, const std::string& outputFile)
|
void CaptureScreenTest::afterCaptured(bool succeed, const std::string& outputFile)
|
||||||
|
|
|
@ -258,6 +258,7 @@ void EffectSprite3D::addEffect(Effect3DOutline* effect, ssize_t order)
|
||||||
{
|
{
|
||||||
if(nullptr == effect) return;
|
if(nullptr == effect) return;
|
||||||
effect->retain();
|
effect->retain();
|
||||||
|
effect->setTarget(this);
|
||||||
|
|
||||||
_effects.push_back(std::make_tuple(order,effect,CustomCommand()));
|
_effects.push_back(std::make_tuple(order,effect,CustomCommand()));
|
||||||
|
|
||||||
|
@ -317,12 +318,14 @@ bool Effect3DOutline::init()
|
||||||
Effect3DOutline::Effect3DOutline()
|
Effect3DOutline::Effect3DOutline()
|
||||||
: _outlineWidth(1.0f)
|
: _outlineWidth(1.0f)
|
||||||
, _outlineColor(1, 1, 1)
|
, _outlineColor(1, 1, 1)
|
||||||
|
, _sprite(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect3DOutline::~Effect3DOutline()
|
Effect3DOutline::~Effect3DOutline()
|
||||||
{
|
{
|
||||||
|
CC_SAFE_RELEASE_NULL(_sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect3DOutline::setOutlineColor(const Vec3& color)
|
void Effect3DOutline::setOutlineColor(const Vec3& color)
|
||||||
|
@ -343,8 +346,16 @@ void Effect3DOutline::setOutlineWidth(float width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Effect3DOutline::drawWithSprite(EffectSprite3D* sprite, const Mat4 &transform)
|
void Effect3DOutline::setTarget(EffectSprite3D *sprite)
|
||||||
{
|
{
|
||||||
|
CCASSERT(nullptr != sprite && nullptr != sprite->getMesh(),"Error: Setting a null pointer or a null mesh EffectSprite3D to Effect3D");
|
||||||
|
|
||||||
|
if(sprite != _sprite)
|
||||||
|
{
|
||||||
|
CC_SAFE_RETAIN(sprite);
|
||||||
|
CC_SAFE_RELEASE_NULL(_sprite);
|
||||||
|
_sprite = sprite;
|
||||||
|
|
||||||
auto mesh = sprite->getMesh();
|
auto mesh = sprite->getMesh();
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
for (auto i = 0; i < mesh->getMeshVertexAttribCount(); i++)
|
for (auto i = 0; i < mesh->getMeshVertexAttribCount(); i++)
|
||||||
|
@ -359,17 +370,24 @@ void Effect3DOutline::drawWithSprite(EffectSprite3D* sprite, const Mat4 &transfo
|
||||||
(void*)offset);
|
(void*)offset);
|
||||||
offset += meshvertexattrib.attribSizeBytes;
|
offset += meshvertexattrib.attribSizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color4F color(_sprite->getDisplayedColor());
|
||||||
|
color.a = _sprite->getDisplayedOpacity() / 255.0f;
|
||||||
|
_glProgramState->setUniformVec4("u_color", Vec4(color.r, color.g, color.b, color.a));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Effect3DOutline::draw(const Mat4 &transform)
|
||||||
|
{
|
||||||
//draw
|
//draw
|
||||||
|
if(_sprite && _sprite->getMesh())
|
||||||
{
|
{
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
glCullFace(GL_FRONT);
|
glCullFace(GL_FRONT);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
Color4F color(sprite->getDisplayedColor());
|
|
||||||
color.a = sprite->getDisplayedOpacity() / 255.0f;
|
|
||||||
|
|
||||||
_glProgramState->setUniformVec4("u_color", Vec4(color.r, color.g, color.b, color.a));
|
auto mesh = _sprite->getMesh();
|
||||||
|
|
||||||
auto mesh = sprite->getMesh();
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer());
|
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer());
|
||||||
_glProgramState->apply(transform);
|
_glProgramState->apply(transform);
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndexBuffer());
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndexBuffer());
|
||||||
|
@ -390,7 +408,7 @@ void EffectSprite3D::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &tran
|
||||||
if(std::get<0>(effect) >=0)
|
if(std::get<0>(effect) >=0)
|
||||||
break;
|
break;
|
||||||
CustomCommand &cc = std::get<2>(effect);
|
CustomCommand &cc = std::get<2>(effect);
|
||||||
cc.func = CC_CALLBACK_0(Effect3D::drawWithSprite,std::get<1>(effect),this,transform);
|
cc.func = CC_CALLBACK_0(Effect3D::draw,std::get<1>(effect),transform);
|
||||||
renderer->addCommand(&cc);
|
renderer->addCommand(&cc);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -402,7 +420,7 @@ void EffectSprite3D::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &tran
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_command.init(_globalZOrder);
|
_command.init(_globalZOrder);
|
||||||
_command.func = CC_CALLBACK_0(Effect3D::drawWithSprite, _defaultEffect, this, transform);
|
_command.func = CC_CALLBACK_0(Effect3D::draw, _defaultEffect, transform);
|
||||||
renderer->addCommand(&_command);
|
renderer->addCommand(&_command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +429,7 @@ void EffectSprite3D::draw(cocos2d::Renderer *renderer, const cocos2d::Mat4 &tran
|
||||||
if(std::get<0>(effect) <=0)
|
if(std::get<0>(effect) <=0)
|
||||||
continue;
|
continue;
|
||||||
CustomCommand &cc = std::get<2>(effect);
|
CustomCommand &cc = std::get<2>(effect);
|
||||||
cc.func = CC_CALLBACK_0(Effect3D::drawWithSprite,std::get<1>(effect),this,transform);
|
cc.func = CC_CALLBACK_0(Effect3D::draw,std::get<1>(effect),transform);
|
||||||
renderer->addCommand(&cc);
|
renderer->addCommand(&cc);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,8 @@ class EffectSprite3D;
|
||||||
class Effect3D : public Ref
|
class Effect3D : public Ref
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void drawWithSprite(EffectSprite3D* sprite, const Mat4 &transform) = 0;
|
virtual void draw(const Mat4 &transform) = 0;
|
||||||
|
virtual void setTarget(EffectSprite3D *sprite) = 0;
|
||||||
protected:
|
protected:
|
||||||
Effect3D() : _glProgramState(nullptr) {}
|
Effect3D() : _glProgramState(nullptr) {}
|
||||||
virtual ~Effect3D()
|
virtual ~Effect3D()
|
||||||
|
@ -85,8 +86,8 @@ public:
|
||||||
|
|
||||||
void setOutlineWidth(float width);
|
void setOutlineWidth(float width);
|
||||||
|
|
||||||
void drawWithSprite(EffectSprite3D* sprite, const Mat4 &transform);
|
virtual void draw(const Mat4 &transform) override;
|
||||||
|
virtual void setTarget(EffectSprite3D *sprite) override;
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Effect3DOutline();
|
Effect3DOutline();
|
||||||
|
@ -96,6 +97,7 @@ protected:
|
||||||
|
|
||||||
Vec3 _outlineColor;
|
Vec3 _outlineColor;
|
||||||
float _outlineWidth;
|
float _outlineWidth;
|
||||||
|
EffectSprite3D* _sprite;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static const std::string _vertShaderFile;
|
static const std::string _vertShaderFile;
|
||||||
|
|
|
@ -8,7 +8,7 @@ On Windows:
|
||||||
* Download python2.7.3 (32bit) from (http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi).
|
* Download python2.7.3 (32bit) from (http://www.python.org/ftp/python/2.7.3/python-2.7.3.msi).
|
||||||
* Add the installed path of python (e.g. C:\Python27) to windows environment variable named 'PATH'.
|
* Add the installed path of python (e.g. C:\Python27) to windows environment variable named 'PATH'.
|
||||||
* Download pyyaml from http://pyyaml.org/download/pyyaml/PyYAML-3.10.win32-py2.7.exe and install it.
|
* Download pyyaml from http://pyyaml.org/download/pyyaml/PyYAML-3.10.win32-py2.7.exe and install it.
|
||||||
* Download pyCheetah from https://raw.github.com/dumganhar/cocos2d-x/download/downloads/Cheetah.zip, unzip it to "C:\Python27\Lib\site-packages"
|
* Download pyCheetah from https://raw.github.com/dumganhar/my_old_cocos2d-x_backup/download/downloads/Cheetah.zip, unzip it to "C:\Python27\Lib\site-packages"
|
||||||
* Set environment variables (`NDK_ROOT`)
|
* Set environment variables (`NDK_ROOT`)
|
||||||
* Go to "cocos2d-x/tools/tolua" folder, and run "genbindings.py". The generated codes will be under "cocos\scripting\auto-generated\js-bindings".
|
* Go to "cocos2d-x/tools/tolua" folder, and run "genbindings.py". The generated codes will be under "cocos\scripting\auto-generated\js-bindings".
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue