diff --git a/test.py b/test.py new file mode 100644 index 0000000..6929b24 --- /dev/null +++ b/test.py @@ -0,0 +1,300 @@ +import parse +import testdata +import unittest +import unittest.mock + + +class TestCase(unittest.TestCase): + ''' + Base test case class + ''' + + def __str__(self): + ''' + Overwrite the standard string representation by an easier to read version. + ''' + # Based on http://stackoverflow.com/a/18460031 + return '.'.join([self.__class__.__module__, self.__class__.__name__, self._testMethodName]) + + def shortDescription(self): + ''' + Disable displaying the first line of the docstring instead of module.class.method. + ''' + # http://www.saltycrane.com/blog/2012/07/how-prevent-nose-unittest-using-docstring-when-verbosity-2/ + return None + + +class TestStrEnum(TestCase): + def test_clean_representation(self): + self.assertEqual(repr(parse.Type.group), 'Type.group') + self.assertEqual(repr(parse.Type.brackets), 'Type.brackets') + self.assertEqual(repr(parse.Modifier.negate), 'Modifier.negate') + self.assertEqual(repr(parse.Modifier.plus), 'Modifier.plus') + + +class TestJSTypes(TestCase): + def test_equality(self): + self.assertEqual(parse.JSBool(True), parse.JSBool(True)) + self.assertEqual(parse.JSBool(False), parse.JSBool(False)) + self.assertNotEqual(parse.JSBool(True), parse.JSBool(False)) + self.assertNotEqual(parse.JSBool(False), parse.JSBool(True)) + + self.assertEqual(parse.JSInt(0), parse.JSInt(0)) + self.assertEqual(parse.JSInt(42), parse.JSInt(42)) + self.assertEqual(parse.JSInt(-13), parse.JSInt(-13)) + self.assertNotEqual(parse.JSInt(0), parse.JSInt(42)) + self.assertNotEqual(parse.JSInt(42), parse.JSInt(0)) + self.assertNotEqual(parse.JSInt(0), parse.JSInt(-13)) + self.assertNotEqual(parse.JSInt(-13), parse.JSInt(42)) + + self.assertEqual(parse.JSString(''), parse.JSString('')) + self.assertEqual(parse.JSString('test'), parse.JSString('test')) + self.assertNotEqual(parse.JSString(''), parse.JSString('test')) + + # Comparisons between different types are currently not supported (JS's equality algorithm is a nightmare) and always return False + self.assertNotEqual(parse.JSBool(True), parse.JSInt(1)) + self.assertNotEqual(parse.JSBool(True), parse.JSString('true')) + + def test_operators(self): + self.assertEqual(parse.JSBool(True) + parse.JSBool(True), parse.JSInt(2)) + self.assertEqual(parse.JSBool(True) + parse.JSInt(41), parse.JSInt(42)) + self.assertEqual(parse.JSBool(True) + parse.JSString('42'), parse.JSString('true42')) + self.assertEqual(parse.JSBool(True) - parse.JSBool(True), parse.JSInt(0)) + self.assertEqual(parse.JSBool(False) - parse.JSBool(True), parse.JSInt(-1)) + self.assertEqual(parse.JSBool(True) - parse.JSInt(3), parse.JSInt(-2)) + self.assertEqual(parse.JSBool(True) - parse.JSString('14'), parse.JSInt(-13)) + self.assertEqual(parse.JSBool(True) - parse.JSString(''), parse.JSInt(1)) + #self.assertEqual(parse.JSBool(True) - parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSBool(True) - parse.JSString('3test'), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSBool(True) * parse.JSBool(True), parse.JSInt(1)) + self.assertEqual(parse.JSBool(False) * parse.JSBool(True), parse.JSInt(0)) + self.assertEqual(parse.JSBool(True) * parse.JSInt(42), parse.JSInt(42)) + self.assertEqual(parse.JSBool(False) * parse.JSInt(42), parse.JSInt(0)) + self.assertEqual(parse.JSBool(True) * parse.JSString('13'), parse.JSInt(13)) + self.assertEqual(parse.JSBool(True) * parse.JSString(''), parse.JSInt(0)) + #self.assertEqual(parse.JSBool(True) * parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSBool(True) * parse.JSString('2test'), parse.JSInt(NaN)) # Not supported + + self.assertEqual(parse.JSInt(13) + parse.JSBool(True), parse.JSInt(14)) + self.assertEqual(parse.JSInt(13) + parse.JSInt(29), parse.JSInt(42)) + self.assertEqual(parse.JSInt(13) + parse.JSString('29'), parse.JSString('1329')) + self.assertEqual(parse.JSInt(13) + parse.JSString(''), parse.JSString('13')) + self.assertEqual(parse.JSInt(13) + parse.JSString('test'), parse.JSString('13test')) + self.assertEqual(parse.JSInt(13) - parse.JSBool(True), parse.JSInt(12)) + self.assertEqual(parse.JSInt(13) - parse.JSInt(12), parse.JSInt(1)) + self.assertEqual(parse.JSInt(13) - parse.JSString('15'), parse.JSInt(-2)) + self.assertEqual(parse.JSInt(13) - parse.JSString(''), parse.JSInt(13)) + #self.assertEqual(parse.JSInt(13) - parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSInt(13) - parse.JSString('13test'), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSInt(3) * parse.JSBool(True), parse.JSInt(3)) + self.assertEqual(parse.JSInt(3) * parse.JSInt(4), parse.JSInt(12)) + self.assertEqual(parse.JSInt(3) * parse.JSString('4'), parse.JSInt(12)) + self.assertEqual(parse.JSInt(3) * parse.JSString(''), parse.JSInt(0)) + #self.assertEqual(parse.JSInt(3) * parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSInt(3) * parse.JSString('1test'), parse.JSInt(NaN)) # Not supported + + self.assertEqual(parse.JSString('1') + parse.JSBool(True), parse.JSString('1true')) + self.assertEqual(parse.JSString('') + parse.JSBool(False), parse.JSString('false')) + self.assertEqual(parse.JSString('test') + parse.JSBool(True), parse.JSString('testtrue')) + self.assertEqual(parse.JSString('1') + parse.JSInt(1), parse.JSString('11')) + self.assertEqual(parse.JSString('1') + parse.JSString('1'), parse.JSString('11')) + self.assertEqual(parse.JSString('13') - parse.JSBool(True), parse.JSInt(12)) + self.assertEqual(parse.JSString('') - parse.JSBool(True), parse.JSInt(-1)) + #self.assertEqual(parse.JSString('test') - parse.JSBool(True), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('3test') - parse.JSBool(True), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSString('1') - parse.JSInt(3), parse.JSInt(-2)) + self.assertEqual(parse.JSString('') - parse.JSInt(-3), parse.JSInt(3)) + #self.assertEqual(parse.JSString('test') - parse.JSInt(13), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('13test') - parse.JSInt(13), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSString('13') - parse.JSString('2'), parse.JSInt(11)) + self.assertEqual(parse.JSString('13') - parse.JSString(''), parse.JSInt(13)) + self.assertEqual(parse.JSString('') - parse.JSString('-3'), parse.JSInt(3)) + #self.assertEqual(parse.JSString('test') - parse.JSString('2'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('13test') - parse.JSString('2'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('2') - parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('2') - parse.JSString('13test'), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSString('3') * parse.JSBool(True), parse.JSInt(3)) + self.assertEqual(parse.JSString('') * parse.JSBool(True), parse.JSInt(0)) + #self.assertEqual(parse.JSString('test') * parse.JSBool(True), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('13test') * parse.JSBool(True), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSString('3') * parse.JSInt(2), parse.JSInt(6)) + self.assertEqual(parse.JSString('') * parse.JSInt(13), parse.JSInt(0)) + #self.assertEqual(parse.JSString('test') * parse.JSInt(1), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('13test') * parse.JSInt(1), parse.JSInt(NaN)) # Not supported + self.assertEqual(parse.JSString('3') * parse.JSString('2'), parse.JSInt(6)) + self.assertEqual(parse.JSString('3') * parse.JSString(''), parse.JSInt(0)) + self.assertEqual(parse.JSString('') * parse.JSString('3'), parse.JSInt(0)) + #self.assertEqual(parse.JSString('3') * parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('') * parse.JSString('test'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('test') * parse.JSString('3'), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('test') * parse.JSString(''), parse.JSInt(NaN)) # Not supported + #self.assertEqual(parse.JSString('3test') * parse.JSString('3'), parse.JSInt(NaN)) # Not supported + + def test_casting(self): + # Casting to Python objects + self.assertEqual(bool(parse.JSBool(True)), True) + self.assertEqual(bool(parse.JSBool(False)), False) + self.assertEqual(int(parse.JSBool(True)), 1) + self.assertEqual(int(parse.JSBool(False)), 0) + self.assertEqual(str(parse.JSBool(True)), 'true') # JavaScript capitalisation! + self.assertEqual(str(parse.JSBool(False)), 'false') + + self.assertEqual(bool(parse.JSInt(0)), False) + self.assertEqual(bool(parse.JSInt(42)), True) + self.assertEqual(int(parse.JSInt(0)), 0) + self.assertEqual(int(parse.JSInt(42)), 42) + self.assertEqual(str(parse.JSInt(0)), '0') + self.assertEqual(str(parse.JSInt(42)), '42') + + self.assertEqual(bool(parse.JSString('')), False) + self.assertEqual(bool(parse.JSString('test')), True) + self.assertEqual(int(parse.JSString('')), 0) + #self.assertEqual(int(parse.JSString('test')), NaN) # Not supported + self.assertEqual(int(parse.JSString('0')), 0) + self.assertEqual(int(parse.JSString('-13')), -13) + self.assertEqual(str(parse.JSString('')), '') + self.assertEqual(str(parse.JSString('test')), 'test') + + # Casting to JS types + self.assertEqual(parse.JSBool(parse.JSBool(True)), parse.JSBool(True)) + self.assertEqual(parse.JSBool(parse.JSBool(False)), parse.JSBool(False)) + self.assertEqual(parse.JSInt(parse.JSBool(True)), parse.JSInt(1)) + self.assertEqual(parse.JSInt(parse.JSBool(False)), parse.JSInt(0)) + self.assertEqual(parse.JSString(parse.JSBool(True)), parse.JSString('true')) # JavaScript capitalisation! + self.assertEqual(parse.JSString(parse.JSBool(False)), parse.JSString('false')) + + self.assertEqual(parse.JSBool(parse.JSInt(0)), parse.JSBool(False)) + self.assertEqual(parse.JSBool(parse.JSInt(42)), parse.JSBool(True)) + self.assertEqual(parse.JSInt(parse.JSInt(0)), parse.JSInt(0)) + self.assertEqual(parse.JSInt(parse.JSInt(42)), parse.JSInt(42)) + self.assertEqual(parse.JSString(parse.JSInt(0)), parse.JSString('0')) + self.assertEqual(parse.JSString(parse.JSInt(42)), parse.JSString('42')) + + self.assertEqual(parse.JSBool(parse.JSString('')), parse.JSBool(False)) + self.assertEqual(parse.JSBool(parse.JSString('test')), parse.JSBool(True)) + #self.assertEqual(parse.JSInt(parse.JSString('')), parse.JSInt(0)) # Not supported (yet?) + #self.assertEqual(parse.JSInt(parse.JSString('test')), parse.JSInt(NaN)) # Not supported (yet?) + self.assertEqual(parse.JSInt(parse.JSString('0')), parse.JSInt(0)) + self.assertEqual(parse.JSInt(parse.JSString('-13')), parse.JSInt(-13)) + self.assertEqual(parse.JSString(parse.JSString('')), parse.JSString('')) + self.assertEqual(parse.JSString(parse.JSString('test')), parse.JSString('test')) + + def test_repr(self): + self.assertEqual(repr(parse.JSBool(True)), 'JSBool(True)') + self.assertEqual(repr(parse.JSBool(False)), 'JSBool(False)') + self.assertEqual(repr(parse.JSInt(0)), 'JSInt(0)') + self.assertEqual(repr(parse.JSInt(-13)), 'JSInt(-13)') + self.assertEqual(repr(parse.JSInt(42)), 'JSInt(42)') + self.assertEqual(repr(parse.JSString('')), "JSString('')") + self.assertEqual(repr(parse.JSString('test')), "JSString('test')") + + +class TestItem(TestCase): + def test_basic(self): + item = parse.Item(parse.Type.group, [], values = []) + item = parse.Item(parse.Type.group, [parse.Modifier.plus], values = []) + with self.assertRaises(ValueError): + parse.Item(-1, []) + with self.assertRaises(TypeError): + parse.Item(parse.Type.brackets, -1) + with self.assertRaises(ValueError): + parse.Item(parse.Type.brackets, [-1]) + with self.assertRaises(ValueError): + parse.Item(parse.Type.group, []) # no values + + def test_evaluate_brackets(self): + def test_brackets(modifiers, result): + self.assertEqual(parse.Item(parse.Type.brackets, modifiers).evaluate(), result) + + test_brackets([], parse.JSString('')) + test_brackets([parse.Modifier.plus], parse.JSInt(0)) + test_brackets([parse.Modifier.negate], parse.JSBool(False)) + # ++[] -> syntax error + test_brackets([parse.Modifier.plus, parse.Modifier.negate], parse.JSInt(0)) + test_brackets([parse.Modifier.negate, parse.Modifier.plus], parse.JSBool(True)) + test_brackets([parse.Modifier.negate, parse.Modifier.negate], parse.JSBool(True)) + # +++[] -> syntax error + # ++![] -> syntax error + test_brackets([parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.plus], parse.JSInt(1)) + test_brackets([parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate], parse.JSInt(1)) + # !++[] -> syntax error + test_brackets([parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate], parse.JSBool(True)) + test_brackets([parse.Modifier.negate, parse.Modifier.negate, parse.Modifier.plus], parse.JSBool(False)) + test_brackets([parse.Modifier.negate, parse.Modifier.negate, parse.Modifier.negate], parse.JSBool(False)) + + def test_evaluate_group(self): + item = parse.Item(parse.Type.group, [], values = []) + with self.assertRaises(ValueError): + item.evaluate() # No evaluateFunction specified + with self.assertRaises(ValueError): + item.evaluate(13) # Not a callable + + mock = unittest.mock.Mock(return_value = 42) + item = parse.Item(parse.Type.group, [], values = [parse.Item(parse.Type.brackets, [parse.Modifier.plus])]) + self.assertEqual(item.evaluate(evaluateFunction = mock), 42) + self.assertEqual(mock.call_count, 1) + self.assertEqual(len(mock.call_args), 2) + self.assertEqual(len(mock.call_args[0]), 2) + self.assertEqual(len(mock.call_args[1]), 0) + self.assertIs(mock.call_args[0][0], item.values) + self.assertIs(mock.call_args[0][1], item.modifiers) + + +class TestFunctions(TestCase): + def test_parse(self): + self.assertEqual(parse.parse('!![]'), [parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate])]) + self.assertEqual(parse.parse('!![]+!+![]'), [ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]), + ]) + self.assertEqual(parse.parse('(!![]+!+![]+[])+(+!![]+[])'), [ + parse.Item(parse.Type.group, [], [ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + parse.Item(parse.Type.group, [], [ + parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + ]) + self.assertEqual(parse.parse('+((!![]+!+![]+[])+(+!![]+[]))'), [ + parse.Item(parse.Type.group, [parse.Modifier.plus], values = [ + parse.Item(parse.Type.group, [], values = [ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.plus, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + parse.Item(parse.Type.group, [], values = [ + parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + ]), + ]) + + def test_evaluate(self): + self.assertEqual(parse.evaluate([parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate])]), parse.JSBool(True)) + self.assertEqual(parse.evaluate([ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + ]), parse.JSInt(2)) + self.assertEqual(parse.evaluate([ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), parse.JSString('2')) + self.assertEqual(parse.evaluate([ + parse.Item(parse.Type.group, [], values = [ + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, [parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + parse.Item(parse.Type.group, [], values = [ + parse.Item(parse.Type.brackets, [parse.Modifier.plus, parse.Modifier.negate, parse.Modifier.negate]), + parse.Item(parse.Type.brackets, []), + ]), + ]), parse.JSString('21')) + + def test_crack(self): + for url, html, result in testdata.data: + self.assertEqual(parse.crack(url, html), parse.JSInt(result)) diff --git a/testdata.py b/testdata.py new file mode 100644 index 0000000..80cae0e --- /dev/null +++ b/testdata.py @@ -0,0 +1,8916 @@ +# Data for the full tests + +data = [ + # (URL, HTML, result) +] + +# Generated using: +# wpull https://archive.today/download/J4I1a.zip --warc-file cloudflare-circumvent --warc-append --warc-max-size 2147483648 --no-robots --no-check-certificate --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0' --concurrent 1 --wait 1 --random-wait --waitretry 1 --page-requisites --span-hosts-allow page-requisites --escaped-fragment --strip-session-id --tries 100 --retry-connrefused --retry-dns-error --timeout 60 --session-timeout 21600 --delete-after --database cloudflare-circumvent.db --no-verbose --output-file cloudflare-circumvent.log +# Extract HTML: +# zgrep -A 84 '' cloudflare-circumvent-00000.warc.gz | sed "s~^--\$~''', None])§data.append(['https://archive.today/download/J4I1a.zip', '''~" | tr '§' '\n' +# Extract challenge code for running in NodeJS: +# { echo "t = 'archive.today'"; echo 'var i = 0;'; zgrep -P '(s,t,o,p,b,r,e,a,k,i,n,g,f|\+ t\.length)' cloudflare-circumvent-00000.warc.gz | sed "s, '; 121',,; s,a\.value =,console.log('data[' + i + '][2] = ' + (,; s,length;$,length));i+=1;,"; } | nodejs + + +# URL and HTML +data.append(['https://archive.today/download/J4I1a.zip', ''' + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376a932d2f3e7a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376a9bdd873eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376aa28cf13e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376aa7e9fb3e7a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376aae69d53e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ab40ced3e74 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376abacd5f3e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376abff9473e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ac4ffc13e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ac8cbb13e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ace79a93e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ad7d9e23e56 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376adbfb2d3e7a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ae51dab3e74 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ae9ae5a3e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376aef08fb3e56 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376af8ab013e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376afd9f733e62 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b04ef2c3e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b0cbf5f3e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b152b733e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b19d8103eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b1d8a7a3ea4 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b23b8053eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b28fed33e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b2e293b3eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b376c3b3e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b3c7c813e80 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b452c253e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b49b9973e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b52ab713e8c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b56dee63eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b5ffb7a3e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b644e2f3e4a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b6cba4b3e62 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b72ddea3e4a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b7b6cd53e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b81fc0d3e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b8b98223e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b909f083ea4 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376b9a1a203eb0 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ba30e253e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ba94a783e62 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bad0d463e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bb4ab0d3e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bbe4e1a3e8c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bc68cb83e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bcc1b133e74 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bd1cf7f3e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bd5f9fb3eb0 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bdcfc3e3e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376be40b703e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bebbc3d3e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bf14e303e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bf7fafd3e98 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376bff590c3eb0 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c084a493e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c11d9f93e56 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c175f3e3e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c1f9bc23e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c2758b63e92 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c2f08733e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c356a883e8c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c3cc9a63e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c42eb7f3e68 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c4bd8c23e56 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c506bf93e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c559a323e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c5ae8423e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c5f4db03eb0 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c65fcb93e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c6dbdeb3e7a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c76de733e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c7b79203ea4 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c84fce03e62 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c8929123e62 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c8eaf113e5c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c92ee853e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c979ea33e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376c9badba3eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ca24e343e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ca78e9d3e6e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cab8e283ea4 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cafaff93e8c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cb76b0a3e98 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cbcdb013eaa + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cc279de3e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cc64dcc3e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ccf5b743e92 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cd33f213ea4 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cdb8c563eb0 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376ce4cce53e50 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cec89563e8c + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cf638c83e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376cfbed4d3e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376d008c113e86 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376d075aac3e9e + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376d0d0c483e4a + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376d14fbc83e74 + |
+
+
+
+
+
+
+
+
+
+
+
+ DDoS protection by Cloudflare
+
+ + Ray ID: 3d376d1e6e573e68 + |
+
+