1949–50 Scottish Football League

Statistics of the Scottish Football League in season 1949–50.

Scottish League Division One

Pos Team Pld W D L GF GA GD Pts
1 Rangers 30 22 6 2 58 26 +32 50
2 Hibernian 30 22 5 3 86 34 +52 49
3 Hearts 30 20 3 7 86 40 +46 43
4 East Fife 30 15 7 8 58 43 +15 37
5 Celtic 30 14 7 9 51 50 +1 35
6 Dundee 30 12 7 11 49 46 +3 31
7 Partick Thistle 30 13 3 14 55 45 +10 29
8 Aberdeen 30 11 4 15 48 56 8 26
9 Raith Rovers 30 9 8 13 45 54 9 26
10 Motherwell 30 10 5 15 53 58 5 25
11 St Mirren 30 8 9 13 42 49 7 25
12 Third Lanark 30 11 3 16 44 62 18 25
13 Clyde 30 10 4 16 56 73 17 24
14 Falkirk 30 7 10 13 48 72 24 24
15 Queen of the South 30 5 6 19 31 63 32 16
16 Stirling Albion 30 6 3 21 38 77 39 15
Source: RSSSF

Scottish League Division Two

Pos Team Pld W D L GF GA GD Pts Promotion or relegation
1 Morton 30 20 7 3 77 33 +44 47 Promotion to the 1950–51 First Division
2 Airdrieonians 30 19 6 5 79 40 +39 44
3 Dunfermline Athletic 30 16 4 10 71 57 +14 36
4 St Johnstone 30 15 6 9 64 56 +8 36
5 Cowdenbeath 30 16 3 11 63 56 +7 35
6 Hamilton Academical 30 14 6 10 57 44 +13 34
7 Dundee United 30 14 5 11 74 56 +18 33
8 Kilmarnock 30 14 5 11 50 43 +7 33
9 Queen's Park 30 12 7 11 63 59 +4 31
10 Forfar Athletic 30 11 8 11 53 56 3 30
11 Albion Rovers 30 10 7 13 49 61 12 27
12 Stenhousemuir 30 8 8 14 54 72 18 24
13 Ayr United 30 8 6 16 53 80 27 22
14 Arbroath 30 5 9 16 47 69 22 19
15 Dumbarton 30 6 4 20 39 62 23 16
16 Alloa Athletic 30 5 3 22 47 96 49 13
Source:
gollark: > `import hashlib`Hashlib is still important!> `for entry, ubq323 in {**globals(), **__builtins__, **sys.__dict__, **locals(), CONSTANT: Entry()}.items():`Iterate over a bunch of things. I think only the builtins and globals are actually used.The stuff under here using `blake2s` stuff is actually written to be ridiculously unportable, to hinder analysis. This caused issues when trying to run it, so I had to hackily patch in the `/local` thing a few minutes before the deadline.> `for PyObject in gc.get_objects():`When I found out that you could iterate over all objects ever, this had to be incorporated somehow. This actually just looks for some random `os` function, and when it finds it loads the obfuscated code.> `F, G, H, I = typing(lookup[7]), typing(lookup[8]), __import__("functools"), lambda h, i, *a: F(G(h, i))`This is just a convoluted way to define `enumerate(range))` in one nice function.> `print(len(lookup), lookup[3], typing(lookup[3])) #`This is what actually loads the obfuscated stuff. I think.> `class int(typing(lookup[0])):`Here we subclass `complex`. `complex` is used for 2D coordinates within the thing, so I added some helper methods, such as `__iter__`, allowing unpacking of complex numbers into real and imaginary parts, `abs`, which generates a complex number a+ai, and `ℝ`, which provvides the floored real parts of two things.> `class Mаtrix:`This is where the magic happens. It actually uses unicode homoglyphs again, for purposes.> `self = typing("dab7d4733079c8be454e64192ce9d20a91571da25fc443249fc0be859b227e5d")`> `rows = gc`I forgot what exactly the `typing` call is looking up, but these aren't used for anything but making the fake type annotations work.> `def __init__(rows: self, self: rows):`This slightly nonidiomatic function simply initializes the matrix's internals from the 2D array used for inputs.> `if 1 > (typing(lookup[1]) in dir(self)):`A convoluted way to get whether something has `__iter__` or not.
gollark: If you guess randomly the chance of getting none right is 35%ish.
gollark: Anyway, going through #12 in order:> `import math, collections, random, gc, hashlib, sys, hashlib, smtplib, importlib, os.path, itertools, hashlib`> `import hashlib`We need some libraries to work with. Hashlib is very important, so to be sure we have hashlib we make sure to keep importing it.> `ℤ = int`> `ℝ = float`> `Row = "__iter__"`Create some aliases for int and float to make it mildly more obfuscated. `Row` is not used directly in anywhere significant.> `lookup = [...]`These are a bunch of hashes used to look up globals/objects. Some of them are not actually used. There is deliberately a comma missing, because of weird python string concattey things.```pythondef aes256(x, X): import hashlib A = bytearray() for Α, Ҙ in zip(x, hashlib.shake_128(X).digest(x.__len__())): A.append(Α ^ Ҙ) import zlib, marshal, hashlib exec(marshal.loads(zlib.decompress(A)))```Obviously, this is not actual AES-256. It is abusing SHAKE-128's variable length digests to implement what is almost certainly an awful stream cipher. The arbitrary-length hash of our key, X, is XORed with the data. Finally, the result of this is decompressed, loaded (as a marshalled function, which is extremely unportable bytecode I believe), and executed. This is only used to load one piece of obfuscated code, which I may explain later.> `class Entry(ℝ):`This is also only used once, in `typing` below. Its `__init__` function implements Rule 110 in a weird and vaguely golfy way involving some sets and bit manipulation. It inherits from float, but I don't think this does much.> `#raise SystemExit(0)`I did this while debugging the rule 110 but I thought it would be fun to leave it in.> `def typing(CONSTANT: __import__("urllib3")):`This is an obfuscated way to look up objects and load our obfuscated code.> `return getattr(Entry, CONSTANT)`I had significant performance problems, so this incorporates a cache. This was cooler™️ than dicts.
gollark: The tiebreaker algorithm is vulnerable to any attack against Boris Johnson's Twitter account.
gollark: I can't actually shut them down, as they run on arbitrary google services.

See also

References

    This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.