2023-09-07, 19:59
  #145
Medlem
Citat:
Ursprungligen postat av Enterprise
För vad det är värt så testa detta. Eftersom vissar matcher på Fullträff inte alltid har odds tydligen (antar att detta kommer så småningom) så gjorde jag en "fall back" där skriptet, när det inte finns odds på webben, istället använder spelarnas streckfördelning som guidance. Tanken är också att det ska gå rejält snabbare, men jag sitter på en lite för slö dator för att kunna avgöra någon stor skillnad.

Kod:
import requests
import re
import json
import itertools
from concurrent.futures import ProcessPoolExecutor

from pprint import pprint


gamemode = int(input("Spelform? 1= Stryktipset 2= Europatipset 3= Fullträff "))

if not gamemode in [1,2,3]:
    print("Endast 1-2 möjliga val. Avbryter.")
    quit()

pgoal = float(input("Önskad summa (t.ex. 200.0) ? "))
pdev = float(input("Tolerabel +/- avvikelse decimaltal (t.ex. 0.05)? "))
pmin = pgoal - pdev
pmax = pgoal + pdev

mde = int(input("Tryck 1 för text-fil och 2 för CSV-fil: "))

if not mde in [1,2]:
    print("Endast 1 eller 2 möjliga val. Avbryter.")
    quit()

urls = ["", "https://spela.svenskaspel.se/stryktipset" , "https://spela.svenskaspel.se/europatipset", "https://spela.svenskaspel.se/fulltraff"]
url = urls[gamemode]

outfiles = ["", "tips.txt", "tips.csv"]
outfile = outfiles[mde]

try: 
	response = requests.get(url)
	html_content = response.text

except:
	print(f"Kan inte komma hämta data från: {url}. Avbryter.")
	quit()

pattern = r'_svs\.tipsen\.data\.preloadedState\s*=\s*(\{.*\});'

try:
	match = re.search(pattern, html_content)
	json_str = match.group(1)
	json_obj = json.loads(json_str)
	gameDict = json_obj["EventTypeStatistic"]
	gameKeys = list(dict.keys(gameDict))

except:
	print(f"Kunde inte extrahera data")
	quit()

signlists = []
rowlist = []

def process_chunk(start, end):
	sub_gen = itertools.islice(itertools.product(*[enumerate(row) for row in rowlist]), start, end)
	valid_combinations = []
	tss = 0
	for comb in sub_gen:
		tss += 1
		indices, values = zip(*comb)
		s = sum(values)
		if pmin <= s <= pmax:
			valid_combinations.append(indices + (s,))
	return valid_combinations, tss

if gamemode == 3:  # om fullträff, sätt upp lista utifrån 13 rader
	draws=json_obj["Draws"]["entities"]
	
	try:
		drawsKey = list(dict.keys(draws))[0]
	except IndexError:
		print("Inte möjligt att hämta Fullträff-omgång. Avbryter.")
		quit()
	
	omg=draws[drawsKey]["drawNumber"] # hämta omgångsnr
	print(f"Fullträff omgång {omg}:")	
	
else:   # annars sätt upp lista utifrån 3 tecken
	for _ in range(0,3):
		signlists.append([])

for gameKey in gameKeys: # iterera över alla 13 matcher
	
	numAlts=3
	if gamemode==3:  # Fullträff
		numAlts=6
	
	game = gameDict[gameKey]["odds"]["current"]["value"]  # hämtar odds-värden från Fullträff-sidan
	
	reserve = False
	
	if game[0] == None:
		reserve = True
		game = gameDict[gameKey]["distributions"]["38"]["Global"]["current"]["value"] #Fall-back till distributions om inte odds finns
	gamesum = 0.0
		
	floats = []
	fgame = []
		
	for i in range(0,numAlts):
		if game[i] == None:
			print ("None-error",gameDict[gameKey])
			quit()
		if reserve == False:
			f = 100.0/float(game[i]) # konvertera oddset 100/o
		else:
			f = float(game[i])
		floats.append(f)
		
	gamesum = sum(floats)
	
	for ix,o in enumerate(floats):
		if reserve == False:
			newo = 100.0 * o / gamesum  # normalfördela fullträff-oddsen så att summan blir 100.0
		else:
			newo = o # om fallback (distribution så behövs ingen normalfördelning)
		
		if ix<numAlts:
			fgame.append(newo)

	if gamemode==3:
		rowlist.append(fgame)
		
	else:
		for ix,perc in enumerate(fgame):
			signlists[ix].append(perc)

	#game = gameDict[gameKey]["distributions"][str(gamemode)]["Global"]["current"]["value"] # Hämta streckfördelning

if gamemode<3:
	
	P = { "1": signlists[0], "X": signlists[1], "2": signlists[2] } 
	rows = itertools.product(*(['1X2'] * 13))

	cn = 0

	with open(outfile, 'w') as f:  
		for row in rows:
			percentage = sum(P[result][n] for (n, result) in enumerate(row))
		
			if  pmin <= percentage <= pmax:
				cn += 1
				if mde==1:
					f.write("E,"+','.join(row)+"\n")
				if mde==2:
					f.write(','.join(row + (str(percentage),))+"\n")
else:
	maxcoupons = 10000
	cn = 0
	tsts = 0
	valid_combinations = []

	chunk_size = 100000  # You can adjust the chunk size
	total_size = 6 ** 13  # 6^13 combinations
	chunks = [(i, min(i + chunk_size, total_size)) for i in range(0, total_size, chunk_size)]

	with ProcessPoolExecutor() as executor:
		for chunk_result, chunk_tsts in executor.map(process_chunk, [start for start, end in chunks], [end for start, end in chunks]):
			tsts += chunk_tsts
			valid_combinations.extend(chunk_result)
			cn += len(chunk_result)

			if tsts % 1000000 == 0:
				print(int(tsts / 1000000), "million iterations,", cn, "rows found")

			if cn >= maxcoupons:
				break
	
	with open(outfile, 'w') as f:
		
		f.write(f"Fulltraff,Omg={omg}\n") # första raden 
		
		for comb in valid_combinations:
			
			if mde == 1: # TXT-läge
				comb=list(comb)
				comb.pop() # ta bort summa som inte används i TXT-läge
				f.write("E,"+','.join(str(nm) for nm in comb)+"\n")
				
			elif mde == 2: # CSV-läge
				f.write(','.join(str(nm) for nm in comb)+"\n")

print(f"{outfile} skapad med {cn} rader!")

Intressant, dock fick jag felmeddelande direkt när jag skulle köra det:

Traceback (most recent call last):

Cell In[2], line 161
for chunk_result, chunk_tsts in executor.map(process_chunk, [start for start, end in chunks], [end for start, end in chunks]):

File ~\anaconda3\Lib\concurrent\futures\process.py:816 in map
results = super().map(partial(_process_chunk, fn),

File ~\anaconda3\Lib\concurrent\futures\_base.py:608 in map
fs = [self.submit(fn, *args) for args in zip(*iterables)]

File ~\anaconda3\Lib\concurrent\futures\_base.py:608 in <listcomp>
fs = [self.submit(fn, *args) for args in zip(*iterables)]

File ~\anaconda3\Lib\concurrent\futures\process.py:770 in submit
raise BrokenProcessPool(self._broken)

BrokenProcessPool: A child process terminated abruptly, the process pool is not usable anymore
Citera
2023-09-07, 20:12
  #146
Medlem
Citat:
Ursprungligen postat av Enterprise
Jag har snickrat på en utbyggnad av skriptet som innebär att det förhoppningvis kommer gå uppemot 10 gånger så snabbt att iterera Fullträff genom parallella trådar. Men problemet är att inte alla matcher just nu är odds-satta, så jag kan inte testa på fullständiga data

Jag visste inte att de ens la ut matcher utan odds, nåväl, annars kanske man bara för att kunna testköra, skulle kunna använda sig av oddsen från i lördags, https://spela.svenskaspel.se/fulltraff/resultat/2023-09-02/statistik

Den möjligheten är ju även intressant för att kunna testa sig fram, om man kan köra ut rader från en tidigare omgångs slutresultat.

Hur som helst så fick jag inte igång det senaste, annars låter ju snabbheten hur grym som helst, så den vill man ju testa.

Jag såg i felmeddelandena att det refereras till anaconda, jag har ju installerat det och lägger in koden i spyder, är det något i den kopplingen som blir fel eller någon extension som saknas ?
Citera
2023-09-07, 20:38
  #147
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Mysadname
Intressant, dock fick jag felmeddelande direkt när jag skulle köra det:

Traceback (most recent call last):

Cell In[2], line 161
for chunk_result, chunk_tsts in executor.map(process_chunk, [start for start, end in chunks], [end for start, end in chunks]):

File ~\anaconda3\Lib\concurrent\futures\process.py:816 in map
results = super().map(partial(_process_chunk, fn),

File ~\anaconda3\Lib\concurrent\futures\_base.py:608 in map
fs = [self.submit(fn, *args) for args in zip(*iterables)]

File ~\anaconda3\Lib\concurrent\futures\_base.py:608 in <listcomp>
fs = [self.submit(fn, *args) for args in zip(*iterables)]

File ~\anaconda3\Lib\concurrent\futures\process.py:770 in submit
raise BrokenProcessPool(self._broken)

BrokenProcessPool: A child process terminated abruptly, the process pool is not usable anymore
Hmm.. fungerar på min MacBook och min Linux-burk. Får kolla på min Windows-burk under helgen.
Kan också vara begränsningar i Anaconda-miljön som stökar till det. Du kör alltså i Spyder och inte i Jupyter Notebook (det står hänvisningar till celler som förekommer i Jupyter)?
Citera
2023-09-07, 20:51
  #148
Medlem
Citat:
Ursprungligen postat av Enterprise
Hmm.. fungerar på min MacBook och min Linux-burk. Får kolla på min Windows-burk under helgen.
Kan också vara begränsningar i Anaconda-miljön som stökar till det. Du kör alltså i Spyder och inte i Jupyter Notebook (det står hänvisningar till celler som förekommer i Jupyter)?

Jag installerade anaconda och spyder då du nämnde det tidigare, ska jag testa med något mer program ?
Citera
2023-09-07, 20:53
  #149
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Mysadname
Jag installerade anaconda och spyder då du nämnde det tidigare, ska jag testa med något mer program ?
Jag är på tjänsteresa och har då inte tillgång till min Windows-burk där jag också kör Anaconda-miljön, så jag vet inte och kan inte ta reda på det förrän under helgen.
Citera
2023-09-07, 21:03
  #150
Medlem
Citat:
Ursprungligen postat av Enterprise
Jag är på tjänsteresa och har då inte tillgång till min Windows-burk där jag också kör Anaconda-miljön, så jag vet inte och kan inte ta reda på det förrän under helgen.

Ah ok, jag tänkte bara om installation av Jupyter kunde lösa det om det refereras till det och jag inte har det installerat och därför inte fungerar
Citera
2023-09-07, 21:09
  #151
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Mysadname
Ah ok, jag tänkte bara om installation av Jupyter kunde lösa det om det refereras till det och jag inte har det installerat och därför inte fungerar
Nä, Jupyter Notebook ingår som standard i Anaconda 3, precis som Spyder och några andra applikationer.
Men om något så har bör Jupyter ha sämre kapacitet än Spyder.
Citera
2023-09-07, 21:10
  #152
Medlem
Citat:
Ursprungligen postat av Enterprise
Nä, Jupyter Notebook ingår som standard i Anaconda 3, precis som Spyder och några andra applikationer.

Ah, ok, och ingen special extension som jag saknar, annars får jag avvakta
Citera
2023-09-09, 09:29
  #153
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Mysadname
Ah, ok, och ingen special extension som jag saknar, annars får jag avvakta
Nu har jag testkört på Windows och Mac och gjort en del ändringar. Detta fungerar på min Spyder-applikation på Windows 11:
Kod:
import requests
import re
import json
import itertools
from concurrent.futures import ProcessPoolExecutor

from pprint import pprint

def process_chunk(start, end, rowlist, pmin, pmax):
	sub_gen = itertools.islice(itertools.product(*[enumerate(row) for row in rowlist]), start, end)
	valid_combinations = []
	tss = 0
	for comb in sub_gen:
		tss += 1
		indices, values = zip(*comb)
		s = sum(values)
		if pmin <= s <= pmax:
			valid_combinations.append(indices + (s,))
	return valid_combinations, tss


def main():
	
	gamemode = int(input("Spelform? 1= Stryktipset 2= Europatipset 3= Fullträff "))

	if not gamemode in [1,2,3]:	
		print("Endast 1-2 möjliga val. Avbryter.")
		quit()

	pgoal = float(input("Önskad summa (t.ex. 200.0) ? "))
	pdev = float(input("Tolerabel +/- avvikelse decimaltal (t.ex. 0.05)? "))
	pmin = pgoal - pdev
	pmax = pgoal + pdev

	mde = int(input("Tryck 1 för text-fil och 2 för CSV-fil: "))

	if not mde in [1,2]:
		print("Endast 1 eller 2 möjliga val. Avbryter.")
		quit()

	urls = ["", "https://spela.svenskaspel.se/stryktipset" , "https://spela.svenskaspel.se/europatipset", "https://spela.svenskaspel.se/fulltraff"]
	url = urls[gamemode]

	outfiles = ["", "tips.txt", "tips.csv"]
	outfile = outfiles[mde]

	try: 
		response = requests.get(url)
		html_content = response.text

	except:
		print(f"Kan inte komma hämta data från: {url}. Avbryter.")
		quit()

	pattern = r'_svs\.tipsen\.data\.preloadedState\s*=\s*(\{.*\});'

	try:
		match = re.search(pattern, html_content)
		json_str = match.group(1)
		json_obj = json.loads(json_str)
		gameDict = json_obj["EventTypeStatistic"]
		gameKeys = list(dict.keys(gameDict))

	except:
		print(f"Kunde inte extrahera data")
		quit()

	signlists = []
	rowlist = []

	if gamemode == 3:  # om fullträff, sätt upp lista utifrån 13 rader
		draws=json_obj["Draws"]["entities"]
	
		try:
			drawsKey = list(dict.keys(draws))[0]
		except IndexError:
			print("Inte möjligt att hämta Fullträff-omgång. Avbryter.")
			quit()
	
		omg=draws[drawsKey]["drawNumber"] # hämta omgångsnr
		print(f"Fullträff omgång {omg}:")	
	
	else:   # annars sätt upp lista utifrån 3 tecken
		for _ in range(0,3):
			signlists.append([])

	for gameKey in gameKeys: # iterera över alla 13 matcher
	
		numAlts=3
		if gamemode==3:  # Fullträff
			numAlts=6
	
		game = gameDict[gameKey]["odds"]["current"]["value"]  # hämtar odds-värden från Fullträff-sidan
		gamesum = 0.0
		
		floats = []
		fgame = []
		
		for i in range(0,numAlts):
			if game[i] == None:
				print ("None-error",gameDict[gameKey])
				quit()
			f = 100.0/float(game[i]) # konvertera oddset 100/o
			floats.append(f)
		
		gamesum = sum(floats)
	
		for ix,o in enumerate(floats):
			newo = 100.0 * o / gamesum  # normalfördela fullträff-oddsen så att summan blir 100.0
			if ix<numAlts:
				fgame.append(newo)

		if gamemode==3:
			rowlist.append(fgame)
		
		else:
			for ix,perc in enumerate(fgame):
				signlists[ix].append(perc)

	if gamemode<3:
	
		P = { "1": signlists[0], "X": signlists[1], "2": signlists[2] } 
		rows = itertools.product(*(['1X2'] * 13))

		cn = 0

		with open(outfile, 'w') as f:  
			for row in rows:
				percentage = sum(P[result][n] for (n, result) in enumerate(row))
		
				if  pmin <= percentage <= pmax:
					cn += 1
					if mde==1:
						f.write("E,"+','.join(row)+"\n")
					if mde==2:
						f.write(','.join(row + (str(percentage),))+"\n")
	else:
		maxcoupons = 10000
		cn = 0
		tsts = 0
		valid_combinations = []

		chunk_size = 100000  # You can adjust the chunk size
		total_size = 6 ** 13  # 6^13 combinations
		chunks = [(i, min(i + chunk_size, total_size)) for i in range(0, total_size, chunk_size)]
	
		print ("Lengt of chunks",len(chunks))
	
		with ProcessPoolExecutor() as executor:
			for chunk_result, chunk_tsts in executor.map(process_chunk, [start for start, end in chunks], [end for start, end in chunks], itertools.repeat(rowlist), itertools.repeat(pmin), itertools.repeat(pmax)):
   
				tsts += chunk_tsts
				valid_combinations.extend(chunk_result)
				cn += len(chunk_result)

				if tsts % 1000000 == 0:
					print(int(tsts / 1000000), "million iterations,", cn, "rows found")

				if cn >= maxcoupons:
					break
	
		with open(outfile, 'w') as f:
		
			f.write(f"Fulltraff,Omg={omg}\n") # första raden 
		
			for ix,comb in enumerate(valid_combinations):
			
				if mde == 1 and ix<maxcoupons: # TXT-läge
					comb=list(comb)
					comb.pop() # ta bort summa som inte används i TXT-läge
					f.write("E,"+','.join(str(nm) for nm in comb)+"\n")
				
				elif mde == 2 and ix<maxcoupons: # CSV-läge
					f.write(','.join(str(nm) for nm in comb)+"\n")

	cn=min(cn,maxcoupons)
	
	print(f"{outfile} skapad med {cn} rader!")

if __name__ == '__main__':
    main()
Det är inte 10 gånger så snabbt som tidigare, men dock snabbare. Eftersom det är parallella processer som körs så verkar skriptet "frysa" i början uppemot 10 sekunder, men sen spottar den ur sig 10-20 miljoner iterationer samtidigt så skriptet jobbar i bakgrunden.
__________________
Senast redigerad av Enterprise 2023-09-09 kl. 09:31.
Citera
2023-09-09, 09:33
  #154
Medlem
Citat:
Ursprungligen postat av Enterprise
Nu har jag testkört på Windows och Mac och gjort en del ändringar. Detta fungerar på min Spyder-applikation på Windows 11:
Kod:
import requests
import re
import json
import itertools
from concurrent.futures import ProcessPoolExecutor

from pprint import pprint

def process_chunk(start, end, rowlist, pmin, pmax):
	sub_gen = itertools.islice(itertools.product(*[enumerate(row) for row in rowlist]), start, end)
	valid_combinations = []
	tss = 0
	for comb in sub_gen:
		tss += 1
		indices, values = zip(*comb)
		s = sum(values)
		if pmin <= s <= pmax:
			valid_combinations.append(indices + (s,))
	return valid_combinations, tss


def main():
	
	gamemode = int(input("Spelform? 1= Stryktipset 2= Europatipset 3= Fullträff "))

	if not gamemode in [1,2,3]:	
		print("Endast 1-2 möjliga val. Avbryter.")
		quit()

	pgoal = float(input("Önskad summa (t.ex. 200.0) ? "))
	pdev = float(input("Tolerabel +/- avvikelse decimaltal (t.ex. 0.05)? "))
	pmin = pgoal - pdev
	pmax = pgoal + pdev

	mde = int(input("Tryck 1 för text-fil och 2 för CSV-fil: "))

	if not mde in [1,2]:
		print("Endast 1 eller 2 möjliga val. Avbryter.")
		quit()

	urls = ["", "https://spela.svenskaspel.se/stryktipset" , "https://spela.svenskaspel.se/europatipset", "https://spela.svenskaspel.se/fulltraff"]
	url = urls[gamemode]

	outfiles = ["", "tips.txt", "tips.csv"]
	outfile = outfiles[mde]

	try: 
		response = requests.get(url)
		html_content = response.text

	except:
		print(f"Kan inte komma hämta data från: {url}. Avbryter.")
		quit()

	pattern = r'_svs\.tipsen\.data\.preloadedState\s*=\s*(\{.*\});'

	try:
		match = re.search(pattern, html_content)
		json_str = match.group(1)
		json_obj = json.loads(json_str)
		gameDict = json_obj["EventTypeStatistic"]
		gameKeys = list(dict.keys(gameDict))

	except:
		print(f"Kunde inte extrahera data")
		quit()

	signlists = []
	rowlist = []

	if gamemode == 3:  # om fullträff, sätt upp lista utifrån 13 rader
		draws=json_obj["Draws"]["entities"]
	
		try:
			drawsKey = list(dict.keys(draws))[0]
		except IndexError:
			print("Inte möjligt att hämta Fullträff-omgång. Avbryter.")
			quit()
	
		omg=draws[drawsKey]["drawNumber"] # hämta omgångsnr
		print(f"Fullträff omgång {omg}:")	
	
	else:   # annars sätt upp lista utifrån 3 tecken
		for _ in range(0,3):
			signlists.append([])

	for gameKey in gameKeys: # iterera över alla 13 matcher
	
		numAlts=3
		if gamemode==3:  # Fullträff
			numAlts=6
	
		game = gameDict[gameKey]["odds"]["current"]["value"]  # hämtar odds-värden från Fullträff-sidan
		gamesum = 0.0
		
		floats = []
		fgame = []
		
		for i in range(0,numAlts):
			if game[i] == None:
				print ("None-error",gameDict[gameKey])
				quit()
			f = 100.0/float(game[i]) # konvertera oddset 100/o
			floats.append(f)
		
		gamesum = sum(floats)
	
		for ix,o in enumerate(floats):
			newo = 100.0 * o / gamesum  # normalfördela fullträff-oddsen så att summan blir 100.0
			if ix<numAlts:
				fgame.append(newo)

		if gamemode==3:
			rowlist.append(fgame)
		
		else:
			for ix,perc in enumerate(fgame):
				signlists[ix].append(perc)

	if gamemode<3:
	
		P = { "1": signlists[0], "X": signlists[1], "2": signlists[2] } 
		rows = itertools.product(*(['1X2'] * 13))

		cn = 0

		with open(outfile, 'w') as f:  
			for row in rows:
				percentage = sum(P[result][n] for (n, result) in enumerate(row))
		
				if  pmin <= percentage <= pmax:
					cn += 1
					if mde==1:
						f.write("E,"+','.join(row)+"\n")
					if mde==2:
						f.write(','.join(row + (str(percentage),))+"\n")
	else:
		maxcoupons = 10000
		cn = 0
		tsts = 0
		valid_combinations = []

		chunk_size = 100000  # You can adjust the chunk size
		total_size = 6 ** 13  # 6^13 combinations
		chunks = [(i, min(i + chunk_size, total_size)) for i in range(0, total_size, chunk_size)]
	
		print ("Lengt of chunks",len(chunks))
	
		with ProcessPoolExecutor() as executor:
			for chunk_result, chunk_tsts in executor.map(process_chunk, [start for start, end in chunks], [end for start, end in chunks], itertools.repeat(rowlist), itertools.repeat(pmin), itertools.repeat(pmax)):
   
				tsts += chunk_tsts
				valid_combinations.extend(chunk_result)
				cn += len(chunk_result)

				if tsts % 1000000 == 0:
					print(int(tsts / 1000000), "million iterations,", cn, "rows found")

				if cn >= maxcoupons:
					break
	
		with open(outfile, 'w') as f:
		
			f.write(f"Fulltraff,Omg={omg}\n") # första raden 
		
			for ix,comb in enumerate(valid_combinations):
			
				if mde == 1 and ix<maxcoupons: # TXT-läge
					comb=list(comb)
					comb.pop() # ta bort summa som inte används i TXT-läge
					f.write("E,"+','.join(str(nm) for nm in comb)+"\n")
				
				elif mde == 2 and ix<maxcoupons: # CSV-läge
					f.write(','.join(str(nm) for nm in comb)+"\n")

	cn=min(cn,maxcoupons)
	
	print(f"{outfile} skapad med {cn} rader!")

if __name__ == '__main__':
    main()
Det är inte 10 gånger så snabbt som tidigare, men dock snabbare. Eftersom det är parallella processer som körs så verkar skriptet "frysa" i början uppemot 10 sekunder, men sen spottar den ur sig 10-20 miljoner iterationer samtidigt så skriptet jobbar i bakgrunden.

Märkligt, jag får inte igång det, vad kan vara fel ?
Citera
2023-09-09, 09:33
  #155
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av Mysadname
Märkligt, jag får inte igång det, vad kan vara fel ?
Felkod?
Citera
2023-09-09, 09:35
  #156
Medlem
Citat:
Ursprungligen postat av Enterprise
Felkod?
Nä, den hoppar bara ner till nästa rad

Eller kanske nu, 2 tryck på ENTER
Citera

Skapa ett konto eller logga in för att kommentera

Du måste vara medlem för att kunna kommentera

Skapa ett konto

Det är enkelt att registrera ett nytt konto

Bli medlem

Logga in

Har du redan ett konto? Logga in här

Logga in