Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
3d0fb53b
Commit
3d0fb53b
authored
Apr 19, 2013
by
Max Lv
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove old shadowsockcs-libev
parent
5bc30e97
Changes
10
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
0 additions
and
1701 deletions
+0
-1701
jni/shadowsocks/android.h
jni/shadowsocks/android.h
+0
-10
jni/shadowsocks/encrypt.c
jni/shadowsocks/encrypt.c
+0
-182
jni/shadowsocks/encrypt.h
jni/shadowsocks/encrypt.h
+0
-39
jni/shadowsocks/local.c
jni/shadowsocks/local.c
+0
-723
jni/shadowsocks/local.h
jni/shadowsocks/local.h
+0
-61
jni/shadowsocks/md5.c
jni/shadowsocks/md5.c
+0
-392
jni/shadowsocks/md5.h
jni/shadowsocks/md5.h
+0
-94
jni/shadowsocks/rc4.c
jni/shadowsocks/rc4.c
+0
-103
jni/shadowsocks/rc4.h
jni/shadowsocks/rc4.h
+0
-55
jni/shadowsocks/socks5.h
jni/shadowsocks/socks5.h
+0
-42
No files found.
jni/shadowsocks/android.h
deleted
100644 → 0
View file @
5bc30e97
#ifndef _ANDROID_H
#define _ANDROID_H
#include <android/log.h>
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "shadowsocks", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "shadowsocks", __VA_ARGS__))
#define perror(a) (LOGE("%s: %s", a, strerror(errno)))
#endif // _ANDROID_H
jni/shadowsocks/encrypt.c
deleted
100755 → 0
View file @
5bc30e97
#include "encrypt.h"
#include "android.h"
#define OFFSET_ROL(p, o) ((u_int64_t)(*(p + o)) << (8 * o))
static
int
random_compare
(
const
void
*
_x
,
const
void
*
_y
)
{
uint32_t
i
=
_i
;
uint64_t
a
=
_a
;
uint8_t
x
=
*
((
uint8_t
*
)
_x
);
uint8_t
y
=
*
((
uint8_t
*
)
_y
);
return
(
a
%
(
x
+
i
)
-
a
%
(
y
+
i
));
}
static
void
md5
(
const
uint8_t
*
text
,
uint8_t
*
digest
)
{
md5_state_t
state
;
md5_init
(
&
state
);
md5_append
(
&
state
,
text
,
strlen
((
char
*
)
text
));
md5_finish
(
&
state
,
digest
);
}
static
void
merge
(
uint8_t
*
left
,
int
llength
,
uint8_t
*
right
,
int
rlength
)
{
/* Temporary memory locations for the 2 segments of the array to merge. */
uint8_t
*
ltmp
=
(
uint8_t
*
)
malloc
(
llength
*
sizeof
(
uint8_t
));
uint8_t
*
rtmp
=
(
uint8_t
*
)
malloc
(
rlength
*
sizeof
(
uint8_t
));
/*
* Pointers to the elements being sorted in the temporary memory locations.
*/
uint8_t
*
ll
=
ltmp
;
uint8_t
*
rr
=
rtmp
;
uint8_t
*
result
=
left
;
/*
* Copy the segment of the array to be merged into the temporary memory
* locations.
*/
memcpy
(
ltmp
,
left
,
llength
*
sizeof
(
uint8_t
));
memcpy
(
rtmp
,
right
,
rlength
*
sizeof
(
uint8_t
));
while
(
llength
>
0
&&
rlength
>
0
)
{
if
(
random_compare
(
ll
,
rr
)
<=
0
)
{
/*
* Merge the first element from the left back into the main array
* if it is smaller or equal to the one on the right.
*/
*
result
=
*
ll
;
++
ll
;
--
llength
;
}
else
{
/*
* Merge the first element from the right back into the main array
* if it is smaller than the one on the left.
*/
*
result
=
*
rr
;
++
rr
;
--
rlength
;
}
++
result
;
}
/*
* All the elements from either the left or the right temporary array
* segment have been merged back into the main array. Append the remaining
* elements from the other temporary array back into the main array.
*/
if
(
llength
>
0
)
while
(
llength
>
0
)
{
/* Appending the rest of the left temporary array. */
*
result
=
*
ll
;
++
result
;
++
ll
;
--
llength
;
}
else
while
(
rlength
>
0
)
{
/* Appending the rest of the right temporary array. */
*
result
=
*
rr
;
++
result
;
++
rr
;
--
rlength
;
}
/* Release the memory used for the temporary arrays. */
free
(
ltmp
);
free
(
rtmp
);
}
static
void
merge_sort
(
uint8_t
array
[],
int
length
)
{
/* This is the middle index and also the length of the right array. */
uint8_t
middle
;
/*
* Pointers to the beginning of the left and right segment of the array
* to be merged.
*/
uint8_t
*
left
,
*
right
;
/* Length of the left segment of the array to be merged. */
int
llength
;
if
(
length
<=
1
)
return
;
/* Let integer division truncate the value. */
middle
=
length
/
2
;
llength
=
length
-
middle
;
/*
* Set the pointers to the appropriate segments of the array to be merged.
*/
left
=
array
;
right
=
array
+
llength
;
merge_sort
(
left
,
llength
);
merge_sort
(
right
,
middle
);
merge
(
left
,
llength
,
right
,
middle
);
}
void
encrypt
(
char
*
buf
,
int
len
,
struct
rc4_state
*
ctx
)
{
if
(
ctx
!=
NULL
)
{
rc4_crypt
(
ctx
,
(
uint8_t
*
)
buf
,
(
uint8_t
*
)
buf
,
len
);
}
else
{
char
*
end
=
buf
+
len
;
while
(
buf
<
end
)
{
*
buf
=
(
char
)
enc_ctx
.
table
.
encrypt_table
[(
uint8_t
)
*
buf
];
buf
++
;
}
}
}
void
decrypt
(
char
*
buf
,
int
len
,
struct
rc4_state
*
ctx
)
{
if
(
ctx
!=
NULL
)
{
rc4_crypt
(
ctx
,
(
uint8_t
*
)
buf
,
(
uint8_t
*
)
buf
,
len
);
}
else
{
char
*
end
=
buf
+
len
;
while
(
buf
<
end
)
{
*
buf
=
(
char
)
enc_ctx
.
table
.
decrypt_table
[(
uint8_t
)
*
buf
];
buf
++
;
}
}
}
void
enc_ctx_init
(
struct
rc4_state
*
ctx
,
int
enc
)
{
uint8_t
*
key
=
enc_ctx
.
rc4
.
key
;
int
key_len
=
enc_ctx
.
rc4
.
key_len
;
rc4_init
(
ctx
,
key
,
key_len
);
}
void
enc_key_init
(
const
char
*
pass
)
{
enc_ctx
.
rc4
.
key_len
=
16
;
enc_ctx
.
rc4
.
key
=
malloc
(
16
);
md5
((
const
uint8_t
*
)
pass
,
enc_ctx
.
rc4
.
key
);
}
void
get_table
(
const
char
*
pass
)
{
uint8_t
*
enc_table
=
malloc
(
256
);
uint8_t
*
dec_table
=
malloc
(
256
);
uint8_t
digest
[
16
];
uint32_t
i
;
md5
((
const
uint8_t
*
)
pass
,
digest
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
_a
+=
OFFSET_ROL
(
digest
,
i
);
}
for
(
i
=
0
;
i
<
256
;
++
i
)
{
enc_table
[
i
]
=
i
;
}
for
(
i
=
1
;
i
<
1024
;
++
i
)
{
_i
=
i
;
merge_sort
(
enc_table
,
256
);
}
for
(
i
=
0
;
i
<
256
;
++
i
)
{
// gen decrypt table from encrypt table
dec_table
[
enc_table
[
i
]]
=
i
;
}
enc_ctx
.
table
.
encrypt_table
=
enc_table
;
enc_ctx
.
table
.
decrypt_table
=
dec_table
;
}
jni/shadowsocks/encrypt.h
deleted
100755 → 0
View file @
5bc30e97
#ifndef _ENCRYPT_H
#define _ENCRYPT_H
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "md5.h"
#include "rc4.h"
#define BUF_SIZE 4096
#define TABLE 0
#define RC4 1
union
{
struct
{
uint8_t
*
encrypt_table
;
uint8_t
*
decrypt_table
;
}
table
;
struct
{
uint8_t
*
key
;
int
key_len
;
}
rc4
;
}
enc_ctx
;
void
get_table
(
const
char
*
key
);
void
encrypt
(
char
*
buf
,
int
len
,
struct
rc4_state
*
ctx
);
void
decrypt
(
char
*
buf
,
int
len
,
struct
rc4_state
*
ctx
);
void
enc_ctx_init
(
struct
rc4_state
*
ctx
,
int
enc
);
void
enc_key_init
(
const
char
*
pass
);
unsigned
int
_i
;
unsigned
long
long
_a
;
int
_method
;
#endif // _ENCRYPT_H
jni/shadowsocks/local.c
deleted
100644 → 0
View file @
5bc30e97
This diff is collapsed.
Click to expand it.
jni/shadowsocks/local.h
deleted
100644 → 0
View file @
5bc30e97
#ifndef _LOCAL_H
#define _LOCAL_H
#include <ev.h>
#include "encrypt.h"
struct
listen_ctx
{
ev_io
io
;
int
fd
;
struct
sockaddr
sock
;
};
struct
server_ctx
{
ev_io
io
;
int
connected
;
struct
server
*
server
;
};
struct
server
{
int
fd
;
char
buf
[
BUF_SIZE
];
// server send from, remote recv into
char
stage
;
int
buf_len
;
struct
rc4_state
*
e_ctx
;
struct
rc4_state
*
d_ctx
;
struct
server_ctx
*
recv_ctx
;
struct
server_ctx
*
send_ctx
;
struct
remote
*
remote
;
};
struct
remote_ctx
{
ev_io
io
;
ev_timer
watcher
;
int
connected
;
struct
remote
*
remote
;
};
struct
remote
{
int
fd
;
char
buf
[
BUF_SIZE
];
// remote send from, server recv into
int
buf_len
;
struct
remote_ctx
*
recv_ctx
;
struct
remote_ctx
*
send_ctx
;
struct
server
*
server
;
};
static
void
accept_cb
(
EV_P_
ev_io
*
w
,
int
revents
);
static
void
server_recv_cb
(
EV_P_
ev_io
*
w
,
int
revents
);
static
void
server_send_cb
(
EV_P_
ev_io
*
w
,
int
revents
);
static
void
remote_recv_cb
(
EV_P_
ev_io
*
w
,
int
revents
);
static
void
remote_send_cb
(
EV_P_
ev_io
*
w
,
int
revents
);
struct
remote
*
new_remote
(
int
fd
);
void
free_remote
(
struct
remote
*
remote
);
void
close_and_free_remote
(
EV_P_
struct
remote
*
remote
);
struct
server
*
new_server
(
int
fd
);
void
free_server
(
struct
server
*
server
);
void
close_and_free_server
(
EV_P_
struct
server
*
server
);
#endif // _LOCAL_H
jni/shadowsocks/md5.c
deleted
100644 → 0
View file @
5bc30e97
This diff is collapsed.
Click to expand it.
jni/shadowsocks/md5.h
deleted
100644 → 0
View file @
5bc30e97
/*
Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/*$Id: md5.h,v 1.1.1.1 2001/10/18 22:50:24 jlovell Exp $ */
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321.
It is derived directly from the text of the RFC and not from the
reference implementation.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef md5_INCLUDED
# define md5_INCLUDED
/*
* This code has some adaptations for the Ghostscript environment, but it
* will compile and run correctly in any environment with 8-bit chars and
* 32-bit ints. Specifically, it assumes that if the following are
* defined, they have the same meaning as in Ghostscript: P1, P2, P3,
* ARCH_IS_BIG_ENDIAN.
*/
typedef
unsigned
char
md5_byte_t
;
/* 8-bit byte */
typedef
unsigned
int
md5_word_t
;
/* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef
struct
md5_state_s
{
md5_word_t
count
[
2
];
/* message length in bits, lsw first */
md5_word_t
abcd
[
4
];
/* digest buffer */
md5_byte_t
buf
[
64
];
/* accumulate block */
}
md5_state_t
;
#ifdef __cplusplus
extern
"C"
{
#endif
/* Initialize the algorithm. */
#ifdef P1
void
md5_init
(
P1
(
md5_state_t
*
pms
));
#else
void
md5_init
(
md5_state_t
*
pms
);
#endif
/* Append a string to the message. */
#ifdef P3
void
md5_append
(
P3
(
md5_state_t
*
pms
,
const
md5_byte_t
*
data
,
int
nbytes
));
#else
void
md5_append
(
md5_state_t
*
pms
,
const
md5_byte_t
*
data
,
int
nbytes
);
#endif
/* Finish the message and return the digest. */
#ifdef P2
void
md5_finish
(
P2
(
md5_state_t
*
pms
,
md5_byte_t
digest
[
16
]));
#else
void
md5_finish
(
md5_state_t
*
pms
,
md5_byte_t
digest
[
16
]);
#endif
#ifdef __cplusplus
}
/* end extern "C" */
#endif
#endif
/* md5_INCLUDED */
jni/shadowsocks/rc4.c
deleted
100644 → 0
View file @
5bc30e97
/*
* rc4.c
*
* Copyright (c) 1996-2000 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.2.2.1 2000/04/18 04:48:31 archie Exp $
*/
#include <stdint.h>
#include "rc4.h"
static
inline
void
swap_bytes
(
u_char
*
a
,
u_char
*
b
)
{
u_char
temp
;
temp
=
*
a
;
*
a
=
*
b
;
*
b
=
temp
;
}
/*
* Initialize an RC4 state buffer using the supplied key,
* which can have arbitrary length.
*/
void
rc4_init
(
struct
rc4_state
*
const
state
,
const
u_char
*
key
,
int
keylen
)
{
u_char
j
;
int
i
;
/* Initialize state with identity permutation */
for
(
i
=
0
;
i
<
256
;
i
++
)
state
->
perm
[
i
]
=
(
u_char
)
i
;
state
->
index1
=
0
;
state
->
index2
=
0
;
/* Randomize the permutation using key data */
for
(
j
=
i
=
0
;
i
<
256
;
i
++
)
{
j
+=
state
->
perm
[
i
]
+
key
[
i
%
keylen
];
swap_bytes
(
&
state
->
perm
[
i
],
&
state
->
perm
[
j
]);
}
}
/*
* Encrypt some data using the supplied RC4 state buffer.
* The input and output buffers may be the same buffer.
* Since RC4 is a stream cypher, this function is used
* for both encryption and decryption.
*/
void
rc4_crypt
(
struct
rc4_state
*
const
state
,
const
u_char
*
inbuf
,
u_char
*
outbuf
,
int
buflen
)
{
int
i
;
u_char
j
;
for
(
i
=
0
;
i
<
buflen
;
i
++
)
{
/* Update modification indicies */
state
->
index1
++
;
state
->
index2
+=
state
->
perm
[
state
->
index1
];
/* Modify permutation */
swap_bytes
(
&
state
->
perm
[
state
->
index1
],
&
state
->
perm
[
state
->
index2
]);
/* Encrypt/decrypt next byte */
j
=
state
->
perm
[
state
->
index1
]
+
state
->
perm
[
state
->
index2
];
outbuf
[
i
]
=
inbuf
[
i
]
^
state
->
perm
[
j
];
}
}
jni/shadowsocks/rc4.h
deleted
100644 → 0
View file @
5bc30e97
/*
* rc4.h
*
* Copyright (c) 1996-2000 Whistle Communications, Inc.
* All rights reserved.
*
* Subject to the following obligations and disclaimer of warranty, use and
* redistribution of this software, in source or object code forms, with or
* without modifications are expressly permitted by Whistle Communications;
* provided, however, that:
* 1. Any and all reproductions of the source or object code must include the
* copyright notice above and the following disclaimer of warranties; and
* 2. No rights are granted, in any manner or form, to use Whistle
* Communications, Inc. trademarks, including the mark "WHISTLE
* COMMUNICATIONS" on advertising, endorsements, or otherwise except as
* such appears in the above copyright notice or in the software.
*
* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.2.2.1 2000/04/18 04:48:32 archie Exp $
*/
#ifndef RC4_H_
#define RC4_H_
typedef
uint8_t
u_char
;
struct
rc4_state
{
u_char
perm
[
256
];
u_char
index1
;
u_char
index2
;
};
void
rc4_init
(
struct
rc4_state
*
state
,
const
u_char
*
key
,
int
keylen
);
void
rc4_crypt
(
struct
rc4_state
*
state
,
const
u_char
*
inbuf
,
u_char
*
outbuf
,
int
buflen
);
#endif
jni/shadowsocks/socks5.h
deleted
100755 → 0
View file @
5bc30e97
#pragma once
#define VERSION 0x05
#define CONNECT 0x01
#define IPV4 0x01
#define DOMAIN 0x03
#define IPV6 0x04
#define CMD_NOT_SUPPORTED 0x07
#pragma pack(1)
struct
method_select_request
{
char
ver
;
char
nmethods
;
char
methods
[
255
];
};
struct
method_select_response
{
char
ver
;
char
method
;
};
struct
socks5_request
{
char
ver
;
char
cmd
;
char
rsv
;
char
atyp
;
};
struct
socks5_response
{
char
ver
;
char
rep
;
char
rsv
;
char
atyp
;
};
#pragma pack()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment