summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordavidovski <david@sendula.com>2022-11-30 10:06:56 +0000
committerdavidovski <david@sendula.com>2022-11-30 10:06:56 +0000
commit290c68795d8100cc97b8b53d80f331e536fc71b1 (patch)
treebf0068c4c9121406df9bc90f5c159fd93de8a61e /src
Added files to repositoryHEADmain
Diffstat (limited to 'src')
-rw-r--r--src/neuralnetwork/clean_data.py59
-rw-r--r--src/neuralnetwork/data/ipa.csv174
-rwxr-xr-xsrc/neuralnetwork/data/names/English.txt3668
-rw-r--r--src/neuralnetwork/generate_alphabets.py44
-rw-r--r--src/neuralnetwork/rnn.py329
-rw-r--r--src/neuralnetwork/training.py373
-rw-r--r--src/neuralnetwork/util.py185
-rw-r--r--src/webserver/dist/index.html122
-rw-r--r--src/webserver/dist/map/afghanistan.pngbin0 -> 23211 bytes
-rw-r--r--src/webserver/dist/map/albania.pngbin0 -> 6638 bytes
-rw-r--r--src/webserver/dist/map/angolia.pngbin0 -> 27027 bytes
-rw-r--r--src/webserver/dist/map/argentina.pngbin0 -> 34781 bytes
-rw-r--r--src/webserver/dist/map/austria.pngbin0 -> 8881 bytes
-rw-r--r--src/webserver/dist/map/azerbaijan.pngbin0 -> 22534 bytes
-rw-r--r--src/webserver/dist/map/background.pngbin0 -> 685688 bytes
-rw-r--r--src/webserver/dist/map/bangladesh.pngbin0 -> 7277 bytes
-rw-r--r--src/webserver/dist/map/botswana.pngbin0 -> 24443 bytes
-rw-r--r--src/webserver/dist/map/brazil.pngbin0 -> 42215 bytes
-rw-r--r--src/webserver/dist/map/brunei.pngbin0 -> 6900 bytes
-rw-r--r--src/webserver/dist/map/bulgaria.pngbin0 -> 22835 bytes
-rw-r--r--src/webserver/dist/map/burundi.pngbin0 -> 7502 bytes
-rw-r--r--src/webserver/dist/map/cambodia.pngbin0 -> 8653 bytes
-rw-r--r--src/webserver/dist/map/cameroon.pngbin0 -> 25309 bytes
-rw-r--r--src/webserver/dist/map/canada.pngbin0 -> 116756 bytes
-rw-r--r--src/webserver/dist/map/chile.pngbin0 -> 19420 bytes
-rw-r--r--src/webserver/dist/map/colombia.pngbin0 -> 26597 bytes
-rw-r--r--src/webserver/dist/map/costa.pngbin0 -> 7024 bytes
-rw-r--r--src/webserver/dist/map/croatia.pngbin0 -> 8524 bytes
-rw-r--r--src/webserver/dist/map/cyprus.pngbin0 -> 8163 bytes
-rw-r--r--src/webserver/dist/map/czech.pngbin0 -> 8929 bytes
-rw-r--r--src/webserver/dist/map/denmark.pngbin0 -> 7671 bytes
-rw-r--r--src/webserver/dist/map/dibouti.pngbin0 -> 7311 bytes
-rw-r--r--src/webserver/dist/map/ecuador.pngbin0 -> 22644 bytes
-rw-r--r--src/webserver/dist/map/estonia.pngbin0 -> 8392 bytes
-rw-r--r--src/webserver/dist/map/ethopia.pngbin0 -> 26251 bytes
-rw-r--r--src/webserver/dist/map/fiji.pngbin0 -> 6769 bytes
-rw-r--r--src/webserver/dist/map/finland.pngbin0 -> 26057 bytes
-rw-r--r--src/webserver/dist/map/haiti.pngbin0 -> 8111 bytes
-rw-r--r--src/webserver/dist/map/honduras.pngbin0 -> 8963 bytes
-rw-r--r--src/webserver/dist/map/hungary.pngbin0 -> 8481 bytes
-rw-r--r--src/webserver/dist/map/iceland.pngbin0 -> 23212 bytes
-rw-r--r--src/webserver/dist/map/india.pngbin0 -> 32085 bytes
-rw-r--r--src/webserver/dist/map/indonesia.pngbin0 -> 36017 bytes
-rw-r--r--src/webserver/dist/map/iran.pngbin0 -> 29620 bytes
-rw-r--r--src/webserver/dist/map/ireland.pngbin0 -> 8956 bytes
-rw-r--r--src/webserver/dist/map/israel.pngbin0 -> 7630 bytes
-rw-r--r--src/webserver/dist/map/italy.pngbin0 -> 25329 bytes
-rw-r--r--src/webserver/dist/map/jamaica.pngbin0 -> 7326 bytes
-rw-r--r--src/webserver/dist/map/lithunia.pngbin0 -> 9185 bytes
-rw-r--r--src/webserver/dist/map/luxemburj.pngbin0 -> 6768 bytes
-rw-r--r--src/webserver/dist/map/macao.pngbin0 -> 6767 bytes
-rw-r--r--src/webserver/dist/map/malaysia.pngbin0 -> 24856 bytes
-rw-r--r--src/webserver/dist/map/malta.pngbin0 -> 6767 bytes
-rw-r--r--src/webserver/dist/map/mauritius.pngbin0 -> 6768 bytes
-rw-r--r--src/webserver/dist/map/mexico.pngbin0 -> 31649 bytes
-rw-r--r--src/webserver/dist/map/moldova.pngbin0 -> 7755 bytes
-rw-r--r--src/webserver/dist/map/namibia.pngbin0 -> 24016 bytes
-rw-r--r--src/webserver/dist/map/netherland.pngbin0 -> 7973 bytes
-rw-r--r--src/webserver/dist/map/nigeria.pngbin0 -> 24703 bytes
-rw-r--r--src/webserver/dist/map/norway.pngbin0 -> 25462 bytes
-rw-r--r--src/webserver/dist/map/panama.pngbin0 -> 8636 bytes
-rw-r--r--src/webserver/dist/map/peru.pngbin0 -> 27826 bytes
-rw-r--r--src/webserver/dist/map/philpine.pngbin0 -> 11118 bytes
-rw-r--r--src/webserver/dist/map/poland.pngbin0 -> 24402 bytes
-rw-r--r--src/webserver/dist/map/portugal.pngbin0 -> 8289 bytes
-rw-r--r--src/webserver/dist/map/puerto_rico.pngbin0 -> 8158 bytes
-rw-r--r--src/webserver/dist/map/russia.pngbin0 -> 98363 bytes
-rw-r--r--src/webserver/dist/map/serbia.pngbin0 -> 22624 bytes
-rw-r--r--src/webserver/dist/map/singapore.pngbin0 -> 7405 bytes
-rw-r--r--src/webserver/dist/map/slovenia.pngbin0 -> 7381 bytes
-rw-r--r--src/webserver/dist/map/south_africa.pngbin0 -> 28681 bytes
-rw-r--r--src/webserver/dist/map/spain.pngbin0 -> 23987 bytes
-rw-r--r--src/webserver/dist/map/sweden.pngbin0 -> 28746 bytes
-rw-r--r--src/webserver/dist/map/switzerland.pngbin0 -> 8243 bytes
-rw-r--r--src/webserver/dist/map/taiwan.pngbin0 -> 7412 bytes
-rw-r--r--src/webserver/dist/map/uk.pngbin0 -> 25004 bytes
-rw-r--r--src/webserver/dist/map/usa.pngbin0 -> 58284 bytes
-rw-r--r--src/webserver/dist/site.js129
-rw-r--r--src/webserver/dist/style.css138
-rw-r--r--src/webserver/dist/subdir/image.pngbin0 -> 226933 bytes
-rw-r--r--src/webserver/dist/subdir/index.html1
-rw-r--r--src/webserver/dist/subdir/test.txt1
-rw-r--r--src/webserver/pom.xml47
-rw-r--r--src/webserver/src/main/java/io/github/davidovski/names/APIRequestHandler.java112
-rw-r--r--src/webserver/src/main/java/io/github/davidovski/names/NameDatabaseManager.java75
-rw-r--r--src/webserver/src/main/java/io/github/davidovski/names/StaticRequestHandler.java85
-rw-r--r--src/webserver/src/main/java/io/github/davidovski/names/WebServer.java51
87 files changed, 5593 insertions, 0 deletions
diff --git a/src/neuralnetwork/clean_data.py b/src/neuralnetwork/clean_data.py
new file mode 100644
index 0000000..345218e
--- /dev/null
+++ b/src/neuralnetwork/clean_data.py
@@ -0,0 +1,59 @@
+import training
+import os
+import sys
+
+if __name__ == "__main__":
+
+ countries = training.get_countries()
+
+ for c, country in countries.items():
+ if c == "uk" or c == "usa":
+
+ # iterate through each dataset separately
+ for dataset, path in country.datasets.items():
+
+ # print information
+ print(f"filtering through {c}'s {dataset}...")
+ sys.stdout.flush()
+
+ names = country.get_names(dataset)
+
+ # store the names that are valid in a seperate list
+ names_output = []
+
+ # load the alphabet file for the country
+ alphabet = []
+
+ with open(os.path.join(country.path, "alphabet.txt"), "r") as file:
+ for l in file.read().split("\n"):
+ alphabet.append(l)
+
+ c = 0
+ t = len(names)
+ # iterate through names in the dataset
+ for name in names:
+ name = country.preprocess(name)
+
+ valid = True
+
+ # invalidate the name if a single letter is not in the alphabet
+ for letter in name:
+ if not letter in alphabet:
+ valid = False
+ break
+
+ if valid:
+ names_output.append(name)
+
+ c += 1
+ if c % 128 == 0:
+ print(f"\r{c}/{t}", end="")
+
+ # print how many names are left
+ print(f"kept {len(names_output)}/{len(names)} names")
+
+ # save dataset
+ with open(path, "w") as file:
+ for name in names_output:
+ file.write(name)
+ file.write("\n")
diff --git a/src/neuralnetwork/data/ipa.csv b/src/neuralnetwork/data/ipa.csv
new file mode 100644
index 0000000..6965ce5
--- /dev/null
+++ b/src/neuralnetwork/data/ipa.csv
@@ -0,0 +1,174 @@
+p,p,vl bilabial plosive
+b,b,vd bilabial plosive
+t,t,vl alveolar plosive
+d,d,vd alveolar plosive
+ʈ,t`,vl retroflex plosive
+ɖ,d`,vd retroflex plosive
+c,c,vl palatal plosive
+ɟ,J\,vd palatal plosive
+k,k,ld velar plosive
+ɡ,g,vd velar plosive
+q,q,vl uvular plosive
+ɢ,G\,vd uvular plosive
+ʔ,?,glottal plosive
+m,m,bilabial nasal
+ɱ,F,vl labiodental nasal
+n,n,alveolar nasal
+ɳ,n`,vl retroflex nasal
+ɲ,J,vl palatal nasal
+ŋ,N,vl velar nasal
+ɴ,N\,vl uvular nasal
+ʙ,B\,vd bilabial trill
+r,r,vd alveolar trill
+ʀ,R\,vl uvular trill
+ɾ,4,vl alveolar tap
+ɽ,r`,vl retroflex flap
+ɸ,p\,vl bilabial fricative
+β,B,vd bilabial fricative
+f,f,vl labiodental fricative
+v,v,vd labiodental fricative
+θ,T,vl dental fricative
+ð,D,vd dental fricative
+s,s,vl alveolar fricative
+z,z,vd alveolar fricative
+ʃ,S,vl postalveolar fricative
+ʒ,Z,vd postalveolar fricative
+ʂ,s`,vl retroflex fricative
+ʐ,z`,vd retroflex fricative
+ç,C,vl palatal fricative
+ʝ,j\,vd palatal fricative
+x,x,vl velar fricative
+ɣ,G,vd velar fricative
+χ,X,vl uvular fricative
+ʁ,R,vd uvular fricative
+ħ,X\,vl pharyngeal fricative
+ʕ,?\,vd pharyngeal fricative
+h,h,vl glottal fricative
+ʔ,?,glottal plosive
+ɬ,K,vl alveolar lateral fricative
+ɮ,K\,vd alveolar lateral fricative
+ʋ,P,vd labiodental approximant
+ɹ,r\,vd (post)alveolar approximant
+ɻ,r\`,vd retroflex approximant
+j,j,vd palatal approximant
+ɰ,M\,vd velar approximant
+l,l,vd alveolar lateral approximant
+ɭ,l`,vd retroflex lateral approximant
+ʎ,L,vd palatal lateral approximant
+ʟ,L\,vd velar lateral approximant
+pʼ,p_>,ejective
+tʼ,t_>,ejective
+ʈʼ,t`_>,ejective
+cʼ,c_>,ejective
+kʼ,k_>,ejective
+qʼ,q_>,ejective
+ɓ,b_<,vl bilabial implosive
+ɗ,d_<,vl alveolar implosive
+ƙ,k_<,vl velar implosive
+ɠ,g_<,vl velar implosive
+i,i,close front unrounded
+y,y,close front rounded
+ɨ,1,close central unrounded
+ʉ,},close central rounded
+ɯ,M,close back unrounded
+u,u,close back rounded
+ɪ,I,lax close front unrounded
+ʏ,Y,lax close front rounded
+ʊ,U,lax close back rounded
+e,e,close-mid front unrounded
+ø,2,front close-mid rounded
+ɤ,7,close-mid back unrounded
+o,o,close-mid back rounded
+ə,@,schwa
+ɘ,@\,close-mid central unrounded vowel
+ɵ,8,rounded schwa
+ɛ,E,open-mid front unrounded
+œ,9,front open-mid rounded
+ʌ,V,open-mid back unrounded
+ɔ,O,open-mid back rounded
+æ,{,mid-open front unrounded vowel
+ɐ,6,open-mid schwa
+a,a,open front unrounded
+ă,a_X,extra short open front unrounded
+ɶ,&,front open rounded
+ɑ,A,open back unrounded
+ɒ,Q,open back rounded
+̥,_0,voiceless
+̬,_v,voiced
+ʰ,_h,aspirated
+̤,_t,breathy voiced
+̰,_k,creaky voiced
+̼,_N,linguolabial
+̪,_d,dental
+̺,_a,apical
+̻,_m,laminal
+̹,_O,more rounded
+̜,_c,less rounded
+̟,_+,advanced
+̠,_-,retracted
+̈,"_""",centralized
+̽,_x,mid-centralized
+̩,=,syllabic
+̯,_^,non-syllabic
+ʷ,_w,labialized
+ʲ,',palatalized
+ˠ,_G,velarized
+ˤ,_?\,pharyngealized
+̴,_e,velarized or pharyngealized
+̝,_r,raised
+̞,_o,lowered
+̃,~,nasalized
+ⁿ,_n,nasal release
+ˡ,_l,lateral release
+̚,_},not audibly released
+̘,_A,advanced tongue root
+̙,_q,retracted tongue root
+̋,_T,extra high tone
+́,_H,high tone
+̄,_M,mid tone
+̀,_L,low tone
+̏,_B,extra low tone
+ˈ,"""",(primary) stress mark
+ˌ,%,secondary stress
+ː,:,length mark
+ˑ,:\,half-length
+̆,_X,extra-short
+.,.,syllable break
+ʍ,W,vl labial-velar fricative
+w,w,vd labio-velar approximant
+ɥ,H,labial-palatal approximant
+ʜ,H\,vl epiglottal fricative
+ʢ,<\,vl epiglottal fricative
+ʡ,>\,vl epiglottal plosive
+ɕ,s\,vl alveolopalatal fricative
+ʑ,z\,vl alveolopalatal fricative
+ʘ,O\,bilabial click
+ǀ,|\,dental click
+ǃ,!\,click
+ǂ,'=\,alveolar click
+ǁ,|\|\,alveolar lateral click
+ɺ,l\,vl alveolar lateral flap
+ɜ,3,open-mid central
+ʛ,G\_<,vl uvular implosive
+ɚ,@`,rhotacized schwa
+ɞ,3\,open-mid central rounded
+ɦ,h\,vd glottal fricative
+ɫ,5,velarized vl alveolar lateral
+ʄ,J\_<,vl palatal implosive
+ʼ,_>,ejective
+ɝ,3`,rhotacized open-mid central
+t͡ʃ,tS,vl postalveolar affricate
+d͡ʒ,dZ,vd postalveolar affricate
+t͡ɕ,ts\,vl alveolo-palatal affricate
+d͡ʑ,dz\,vd alveolo-palatal affricate
+t͡ɬ,tK,vl alveolar lateral affricate
+k͡p,kp,vl labial-velar plosive
+g͡b,gb,vd labial-velar plosive
+ŋ͡m,Nm,labial-velar nasal stop
+ʈ͡ʂ,ts`,vl retroflex affricate
+ɖ͡ʐ,tz`,vd retroflex affricate
+˩,_B,extra low tone
+˨,_L,low tone
+˧,_M,mid tone
+˦,_H,high tone
+˥,_T,extra high tone
diff --git a/src/neuralnetwork/data/names/English.txt b/src/neuralnetwork/data/names/English.txt
new file mode 100755
index 0000000..2b943a7
--- /dev/null
+++ b/src/neuralnetwork/data/names/English.txt
@@ -0,0 +1,3668 @@
+Abbas
+Abbey
+Abbott
+Abdi
+Abel
+Abraham
+Abrahams
+Abrams
+Ackary
+Ackroyd
+Acton
+Adair
+Adam
+Adams
+Adamson
+Adanet
+Addams
+Adderley
+Addinall
+Addis
+Addison
+Addley
+Aderson
+Adey
+Adkins
+Adlam
+Adler
+Adrol
+Adsett
+Agar
+Ahern
+Aherne
+Ahmad
+Ahmed
+Aikman
+Ainley
+Ainsworth
+Aird
+Airey
+Aitchison
+Aitken
+Akhtar
+Akram
+Alam
+Alanson
+Alber
+Albert
+Albrighton
+Albutt
+Alcock
+Alden
+Alder
+Aldersley
+Alderson
+Aldred
+Aldren
+Aldridge
+Aldworth
+Alesbury
+Alexandar
+Alexander
+Alexnader
+Alford
+Algar
+Ali
+Alker
+Alladee
+Allam
+Allan
+Allard
+Allaway
+Allcock
+Allcott
+Alldridge
+Alldritt
+Allen
+Allgood
+Allington
+Alliott
+Allison
+Allkins
+Allman
+Allport
+Allsop
+Allum
+Allwood
+Almond
+Alpin
+Alsop
+Altham
+Althoff
+Alves
+Alvey
+Alway
+Ambrose
+Amesbury
+Amin
+Amner
+Amod
+Amor
+Amos
+Anakin
+Anderson
+Andersson
+Anderton
+Andrew
+Andrews
+Angus
+Anker
+Anley
+Annan
+Anscombe
+Ansell
+Anstee
+Anthony
+Antic
+Anton
+Antony
+Antram
+Anwar
+Appleby
+Appleton
+Appleyard
+Apsley
+Arah
+Archer
+Ardern
+Arkins
+Armer
+Armitage
+Armour
+Armsden
+Armstrong
+Arnall
+Arnett
+Arnold
+Arnott
+Arrowsmith
+Arscott
+Arthur
+Artliff
+Ashbridge
+Ashbrook
+Ashby
+Ashcroft
+Ashdown
+Ashe
+Asher
+Ashford
+Ashley
+Ashman
+Ashton
+Ashurst
+Ashwell
+Ashworth
+Askew
+Aslam
+Asom
+Aspey
+Aspin
+Aspinall
+Astbury
+Astle
+Astley
+Aston
+Atherley
+Atherstone
+Atherton
+Atkin
+Atkins
+Atkinson
+Attard
+Atter
+Atterbury
+Atterton
+Attewell
+Attrill
+Attwood
+Auberton
+Auborn
+Aubrey
+Austen
+Austin
+Auton
+Avenue
+Avery
+Aves
+Avis
+Awad
+Axon
+Aylett
+Ayley
+Ayliffe
+Ayling
+Aylott
+Aylward
+Ayres
+Ayton
+Aziz
+Bacon
+Bailey
+Bain
+Bainbridge
+Baines
+Bains
+Baird
+Baker
+Baldwin
+Bale
+Ball
+Ballantyne
+Ballard
+Bamford
+Bancroft
+Banks
+Banner
+Bannister
+Barber
+Barclay
+Barker
+Barlow
+Barnard
+Barnes
+Barnett
+Baron
+Barr
+Barrett
+Barron
+Barrow
+Barry
+Bartlett
+Barton
+Bass
+Bassett
+Batchelor
+Bate
+Bateman
+Bates
+Batt
+Batten
+Batty
+Baxter
+Bayliss
+Beadle
+Beal
+Beale
+Beamish
+Bean
+Bear
+Beattie
+Beatty
+Beaumont
+Beck
+Bedford
+Beech
+Beer
+Begum
+Bell
+Bellamy
+Benfield
+Benjamin
+Bennett
+Benson
+Bentley
+Berger
+Bernard
+Berry
+Best
+Bethell
+Betts
+Bevan
+Beveridge
+Bickley
+Biddle
+Biggs
+Bill
+Bing
+Bingham
+Binnington
+Birch
+Bird
+Bishop
+Bithell
+Black
+Blackburn
+Blackman
+Blackmore
+Blackwell
+Blair
+Blake
+Blakeley
+Blakey
+Blanchard
+Bland
+Bloggs
+Bloom
+Blundell
+Blythe
+Bob
+Boden
+Boland
+Bolton
+Bond
+Bone
+Bonner
+Boon
+Booth
+Borland
+Bostock
+Boulton
+Bourne
+Bouvet
+Bowden
+Bowen
+Bower
+Bowers
+Bowes
+Bowler
+Bowles
+Bowman
+Boyce
+Boyd
+Boyle
+Bracey
+Bradbury
+Bradley
+Bradshaw
+Brady
+Brain
+Braithwaite
+Bramley
+Brandrick
+Bray
+Breen
+Brelsford
+Brennan
+Brett
+Brewer
+Bridges
+Briggs
+Bright
+Bristow
+Britton
+Broadbent
+Broadhurst
+Broadley
+Brock
+Brook
+Brooke
+Brooker
+Brookes
+Brookfield
+Brooks
+Broomfield
+Broughton
+Brown
+Browne
+Browning
+Bruce
+Brunet
+Brunton
+Bryan
+Bryant
+Bryson
+Buchan
+Buchanan
+Buck
+Buckingham
+Buckley
+Budd
+Bugg
+Bull
+Bullock
+Burch
+Burden
+Burdett
+Burford
+Burge
+Burgess
+Burke
+Burland
+Burman
+Burn
+Burnett
+Burns
+Burr
+Burrows
+Burt
+Burton
+Busby
+Bush
+Butcher
+Butler
+Butt
+Butter
+Butterworth
+Button
+Buxton
+Byrne
+Caddy
+Cadman
+Cahill
+Cain
+Cairns
+Caldwell
+Callaghan
+Callow
+Calveley
+Calvert
+Cameron
+Campbell
+Cann
+Cannon
+Caplan
+Capper
+Carey
+Carling
+Carmichael
+Carnegie
+Carney
+Carpenter
+Carr
+Carrington
+Carroll
+Carruthers
+Carson
+Carter
+Cartwright
+Carty
+Casey
+Cashmore
+Cassidy
+Caton
+Cavanagh
+Cawley
+Chadwick
+Chalmers
+Chamberlain
+Chambers
+Chan
+Chance
+Chandler
+Chantler
+Chaplin
+Chapman
+Chappell
+Chapple
+Charge
+Charles
+Charlton
+Charnock
+Chase
+Chatterton
+Chauhan
+Cheetham
+Chelmy
+Cherry
+Cheshire
+Chester
+Cheung
+Chidlow
+Child
+Childs
+Chilvers
+Chisholm
+Chong
+Christie
+Christy
+Chung
+Church
+Churchill
+Clamp
+Clancy
+Clark
+Clarke
+Clarkson
+Clay
+Clayton
+Cleary
+Cleaver
+Clegg
+Clements
+Cliff
+Clifford
+Clifton
+Close
+Clough
+Clowes
+Coates
+Coburn
+Cochrane
+Cockburn
+Cockle
+Coffey
+Cohen
+Cole
+Coleman
+Coles
+Coll
+Collard
+Collett
+Colley
+Collier
+Collingwood
+Collins
+Collinson
+Colman
+Compton
+Conneely
+Connell
+Connelly
+Connolly
+Connor
+Conrad
+Conroy
+Conway
+Cook
+Cooke
+Cookson
+Coomber
+Coombes
+Cooper
+Cope
+Copeland
+Copland
+Copley
+Corbett
+Corcoran
+Core
+Corlett
+Cormack
+Corner
+Cornish
+Cornock
+Corr
+Corrigan
+Cosgrove
+Costa
+Costello
+Cotter
+Cotterill
+Cotton
+Cottrell
+Couch
+Coulson
+Coulter
+Court
+Cousin
+Cousins
+Cove
+Cowan
+Coward
+Cowell
+Cowie
+Cowley
+Cox
+Coyle
+Crabb
+Crabtree
+Cracknell
+Craig
+Crane
+Craven
+Crawford
+Crawley
+Creasey
+Cresswell
+Crew
+Cripps
+Crisp
+Crocker
+Croft
+Crofts
+Cronin
+Crook
+Crosby
+Cross
+Crossland
+Crossley
+Crouch
+Croucher
+Crow
+Crowe
+Crowley
+Crown
+Crowther
+Crump
+Cullen
+Cumming
+Cummings
+Cummins
+Cunningham
+Curley
+Curran
+Currie
+Curry
+Curtis
+Curwood
+Cutts
+D arcy
+Dacey
+Dack
+Dalby
+Dale
+Daley
+Dallas
+Dalton
+Daly
+Dalzell
+Damon
+Danby
+Dandy
+Daniel
+Daniells
+Daniels
+Danks
+Dann
+Darby
+Darbyshire
+Darcy
+Dardenne
+Darlington
+Darr
+Daugherty
+Davenport
+Davey
+David
+Davidson
+Davie
+Davies
+Davis
+Davison
+Davy
+Dawe
+Dawes
+Dawkins
+Dawson
+Day
+Dayman
+De ath
+Deacon
+Deakin
+Dean
+Deane
+Deans
+Debenham
+Deegan
+Deeley
+Deighton
+Delamarre
+Delaney
+Dell
+Dempsey
+Dempster
+Denby
+Denham
+Denis
+Denney
+Dennis
+Dent
+Denton
+Depp
+Dermody
+Derrick
+Derrien
+Dervish
+Desai
+Devaney
+Devenish
+Deverell
+Devine
+Devlin
+Devon
+Devonport
+Dewar
+Dexter
+Diamond
+Dibble
+Dick
+Dickens
+Dickenson
+Dicker
+Dickinson
+Dickson
+Dillon
+Dimmock
+Dingle
+Dipper
+Dixon
+Dobbin
+Dobbins
+Doble
+Dobson
+Docherty
+Docker
+Dodd
+Dodds
+Dodson
+Doherty
+Dolan
+Dolcy
+Dolman
+Dolton
+Donald
+Donaldson
+Donkin
+Donlan
+Donn
+Donnachie
+Donnelly
+Donoghue
+Donohoe
+Donovan
+Dooley
+Doolin
+Doon
+Doors
+Dora
+Doran
+Dorman
+Dornan
+Dorrian
+Dorrington
+Dougal
+Dougherty
+Doughty
+Douglas
+Douthwaite
+Dove
+Dover
+Dowell
+Dowler
+Dowling
+Down
+Downer
+Downes
+Downey
+Downie
+Downing
+Downs
+Downton
+Dowson
+Doyle
+Drabble
+Drain
+Drake
+Draper
+Drew
+Drewett
+Dreyer
+Driffield
+Drinkwater
+Driscoll
+Driver
+Drummond
+Drury
+Drysdale
+Dubois
+Duck
+Duckworth
+Ducon
+Dudley
+Duff
+Duffield
+Duffin
+Duffy
+Dufour
+Duggan
+Duke
+Dukes
+Dumont
+Duncan
+Dundon
+Dunford
+Dunkley
+Dunlop
+Dunmore
+Dunn
+Dunne
+Dunnett
+Dunning
+Dunsford
+Dupont
+Durand
+Durant
+Durber
+Durham
+Durrant
+Dutt
+Duval
+Duvall
+Dwyer
+Dyde
+Dyer
+Dyerson
+Dykes
+Dymond
+Dymott
+Dyson
+Eade
+Eadie
+Eagle
+Eales
+Ealham
+Ealy
+Eames
+Eansworth
+Earing
+Earl
+Earle
+Earley
+Easdale
+Easdown
+Easen
+Eason
+East
+Eastaugh
+Eastaway
+Eastell
+Easterbrook
+Eastham
+Easton
+Eastwood
+Eatherington
+Eaton
+Eaves
+Ebbs
+Ebden
+Ebdon
+Ebeling
+Eburne
+Eccles
+Eccleston
+Ecclestone
+Eccott
+Eckersall
+Eckersley
+Eddison
+Eddleston
+Eddy
+Eden
+Edeson
+Edgar
+Edge
+Edgell
+Edgerton
+Edgley
+Edgson
+Edkins
+Edler
+Edley
+Edlington
+Edmond
+Edmonds
+Edmondson
+Edmunds
+Edmundson
+Edney
+Edon
+Edwards
+Edwick
+Eedie
+Egan
+Egerton
+Eggby
+Eggison
+Eggleston
+Eglan
+Egleton
+Eglin
+Eilers
+Ekin
+Elbutt
+Elcock
+Elder
+Eldeston
+Eldridge
+Eley
+Elfman
+Elford
+Elkin
+Elkington
+Ellam
+Ellans
+Ellard
+Elleray
+Ellerby
+Ellershaw
+Ellery
+Elliman
+Elling
+Ellingham
+Elliot
+Elliott
+Ellis
+Ellison
+Elliston
+Ellrott
+Ellwood
+Elmer
+Elmes
+Elmhirst
+Elmore
+Elms
+Elphick
+Elsdon
+Elsmore
+Elson
+Elston
+Elstone
+Eltis
+Elven
+Elvin
+Elvins
+Elwell
+Elwood
+Elworthy
+Elzer
+Emberey
+Emberson
+Embleton
+Emerick
+Emerson
+Emery
+Emmanuel
+Emmerson
+Emmery
+Emmett
+Emmings
+Emmins
+Emmons
+Emmott
+Emms
+Emsden
+Endroe
+England
+English
+Ennis
+Ennos
+Enright
+Enticott
+Entwistle
+Epsom
+Epton
+Ernest
+Erridge
+Errington
+Errity
+Esan
+Escott
+Eskins
+Eslick
+Espley
+Essam
+Essan
+Essop
+Estlick
+Etchells
+Etheridge
+Etherington
+Etherton
+Ettrick
+Evans
+Evason
+Evenden
+Everdell
+Everett
+Everill
+Everitt
+Everson
+Everton
+Eveson
+Evison
+Evrard
+Ewart
+Ewin
+Ewing
+Ewles
+Exley
+Exon
+Exton
+Eyett
+Eyles
+Eyre
+Eyres
+Fabb
+Fagan
+Fagon
+Fahy
+Fairbairn
+Fairbrace
+Fairbrother
+Fairchild
+Fairclough
+Fairhurst
+Fairley
+Fairlie
+Fairweather
+Falconer
+Falk
+Fall
+Fallon
+Fallows
+Falsh
+Farge
+Fargher
+Farhall
+Farley
+Farmer
+Farnsworth
+Farnum
+Farnworth
+Farr
+Farrant
+Farrar
+Farre
+Farrell
+Farrelly
+Farren
+Farrer
+Farrier
+Farrington
+Farrow
+Faulkner
+Faust
+Fawcett
+Fawn
+Faye
+Fearn
+Fearnley
+Fearns
+Fearon
+Featherstone
+Feeney
+Feetham
+Felix
+Fell
+Fellmen
+Fellows
+Feltham
+Felton
+Fenlon
+Fenn
+Fenton
+Fenwick
+Ferdinand
+Fereday
+Ferguson
+Fern
+Fernandez
+Ferns
+Fernyhough
+Ferreira
+Ferrier
+Ferris
+Ferry
+Fewtrell
+Field
+Fielder
+Fielding
+Fields
+Fifield
+Finan
+Finbow
+Finch
+Findlay
+Findley
+Finlay
+Finn
+Finnegan
+Finney
+Finnigan
+Finnimore
+Firth
+Fischer
+Fish
+Fisher
+Fishlock
+Fisk
+Fitch
+Fitchett
+Fitton
+Fitzgerald
+Fitzpatrick
+Fitzsimmons
+Flack
+Flaherty
+Flanagan
+Flanders
+Flannery
+Flavell
+Flaxman
+Fleetwood
+Fleming
+Fletcher
+Flett
+Florey
+Floss
+Flower
+Flowers
+Floyd
+Flynn
+Foden
+Fogg
+Foley
+Fontaine
+Foran
+Forbes
+Ford
+Forde
+Fordham
+Foreman
+Forester
+Forman
+Forrest
+Forrester
+Forshaw
+Forster
+Forsyth
+Forsythe
+Forth
+Fortin
+Foss
+Fossard
+Fosse
+Foster
+Foston
+Fothergill
+Fotheringham
+Foucher
+Foulkes
+Fountain
+Fowler
+Fowley
+Fox
+Foxall
+Foxley
+Frame
+Frampton
+France
+Francis
+Franco
+Frankish
+Frankland
+Franklin
+Franks
+Frary
+Fraser
+Frazer
+Frederick
+Frederikson
+Freeburn
+Freedman
+Freeman
+Freestone
+Freeth
+Freight
+French
+Fretwell
+Frey
+Fricker
+Friel
+Friend
+Frith
+Froggatt
+Froggett
+Frost
+Frostick
+Froy
+Frusher
+Fryer
+Fulker
+Fuller
+Fulleron
+Fullerton
+Fulton
+Funnell
+Furey
+Furlong
+Furnell
+Furness
+Furnish
+Furniss
+Furse
+Fyall
+Gadsden
+Gaffney
+Galbraith
+Gale
+Gales
+Gall
+Gallacher
+Gallagher
+Galliford
+Gallo
+Galloway
+Galvin
+Gamble
+Gammer
+Gammon
+Gander
+Gandham
+Ganivet
+Garber
+Garbett
+Garbutt
+Garcia
+Gardener
+Gardiner
+Gardner
+Garland
+Garner
+Garrard
+Garratt
+Garrett
+Garside
+Garvey
+Gascoyne
+Gaskell
+Gately
+Gates
+Gaudin
+Gaumont
+Gauntlett
+Gavin
+Gaynor
+Geaney
+Geary
+Geeson
+Geldard
+Geldart
+Gell
+Gemmell
+Gene
+George
+Gerard
+Gerrard
+Geyer
+Gibb
+Gibbins
+Gibbon
+Gibbons
+Gibbs
+Giblin
+Gibson
+Gifford
+Gilbert
+Gilbey
+Gilchrist
+Gilder
+Giles
+Gilfillan
+Gilks
+Gill
+Gillam
+Gillan
+Gillard
+Gillen
+Gillespie
+Gillett
+Gillies
+Gilmartin
+Gilmore
+Gilmour
+Ginty
+Girdwood
+Girling
+Given
+Gladwell
+Glaister
+Glasby
+Glasgow
+Glass
+Gleave
+Gledhill
+Gleeson
+Glen
+Glencross
+Glenn
+Glennie
+Glennon
+Glew
+Glossop
+Glover
+Glynn
+Goble
+Godby
+Goddard
+Godden
+Godfrey
+Godwin
+Goff
+Gold
+Goldberg
+Golding
+Goldman
+Goldsmith
+Goldsworthy
+Gomez
+Gonzalez
+Gooch
+Good
+Goodacre
+Goodall
+Goodchild
+Goode
+Gooding
+Goodman
+Goodridge
+Goodson
+Goodwin
+Goodyear
+Gordon
+Goring
+Gorman
+Gosden
+Gosling
+Gough
+Gould
+Goulden
+Goulding
+Gourlay
+Govender
+Govier
+Gower
+Gowing
+Grady
+Graham
+Grainger
+Grange
+Granger
+Grant
+Graves
+Gray
+Grayson
+Greaves
+Green
+Greenall
+Greenaway
+Greene
+Greener
+Greenhill
+Greening
+Greenleaf
+Greenshields
+Greenslade
+Greensmith
+Greenway
+Greenwood
+Greer
+Gregory
+Greig
+Grenard
+Grennan
+Gresham
+Grey
+Grierson
+Griff
+Griffin
+Griffith
+Griffiths
+Griggs
+Grimes
+Grimshaw
+Grinham
+Grivet
+Grogan
+Groom
+Grose
+Grosvenor
+Grout
+Groves
+Grundy
+Guest
+Guilmard
+Guinard
+Gulley
+Gunby
+Gunn
+Gunning
+Gunston
+Gunter
+Guthrie
+Gutteridge
+Guttridge
+Hackett
+Hadden
+Haddock
+Hadfield
+Hagan
+Haggett
+Haigh
+Haine
+Haines
+Hale
+Halford
+Hall
+Hallam
+Hallett
+Halliday
+Halliwell
+Halstead
+Hamer
+Hamill
+Hamilton
+Hammond
+Hamnett
+Hampson
+Hampton
+Hancock
+Hand
+Handley
+Hanlon
+Hannam
+Hansen
+Hanson
+Harden
+Harding
+Hardwick
+Hardy
+Hargreaves
+Harker
+Harkness
+Harley
+Harlow
+Harman
+Harness
+Harper
+Harries
+Harrington
+Harris
+Harrison
+Harrop
+Harry
+Hart
+Hartley
+Harvey
+Harwood
+Haslam
+Hassan
+Hassani
+Hastings
+Hatch
+Hatton
+Hawes
+Hawker
+Hawkes
+Hawkins
+Hawkridge
+Hawley
+Haworth
+Hawtin
+Hayes
+Haynes
+Hayward
+Head
+Healey
+Healy
+Heath
+Heathcote
+Heather
+Heatley
+Heaton
+Hedley
+Hegney
+Helley
+Hellier
+Helm
+Hemingway
+Hemmings
+Henderson
+Hendry
+Heneghan
+Hennessy
+Henry
+Hepburn
+Hepples
+Herbert
+Heritage
+Heron
+Herron
+Hetherington
+Hewitt
+Hewlett
+Heywood
+Hibbert
+Hickey
+Hickman
+Hicks
+Higgins
+Higginson
+Higgs
+Hill
+Hills
+Hilton
+Hind
+Hinde
+Hindle
+Hindley
+Hinds
+Hine
+Hinton
+Hirst
+Hiscocks
+Hitchcock
+Hoare
+Hobbs
+Hobson
+Hocking
+Hodder
+Hodge
+Hodges
+Hodgkins
+Hodgkinson
+Hodgson
+Hodkinson
+Hodson
+Hogan
+Hogg
+Holden
+Holder
+Holding
+Holdsworth
+Hole
+Holgate
+Holl
+Holland
+Hollis
+Holloway
+Holman
+Holmes
+Holt
+Homer
+Hood
+Hook
+Hooper
+Hooton
+Hope
+Hopes
+Hopkins
+Hopkinson
+Hopwood
+Horn
+Horne
+Horner
+Horrocks
+Horton
+Hough
+Houghton
+Hoult
+Houlton
+Houston
+Howard
+Howarth
+Howden
+Howe
+Howell
+Howells
+Howes
+Howie
+Hoyle
+Hubbard
+Hudson
+Huggins
+Hughes
+Hull
+Hulme
+Hume
+Humphrey
+Humphreys
+Humphries
+Hunt
+Hunter
+Hurley
+Hurrell
+Hurst
+Hussain
+Hussein
+Hussey
+Hutchings
+Hutchins
+Hutchinson
+Hutchison
+Hutton
+Hyde
+Ianson
+Ibbotson
+Ibbs
+Ibrahim
+Iddon
+Iggleden
+Iles
+Ilett
+Illing
+Illingworth
+Ilsley
+Impey
+Imran
+Ingermann
+Ingham
+Ingle
+Ingleby
+Ingledew
+Inglefield
+Ingles
+Inglethorpe
+Ingram
+Inker
+Inman
+Innalls
+Innes
+Inson
+Ireland
+Ireson
+Ironman
+Ironmonger
+Irvin
+Irvine
+Irving
+Irwin
+Isaac
+Isaacs
+Isbill
+Isbitt
+Isgate
+Isherwod
+Isherwood
+Islam
+Isman
+Isnard
+Issac
+Ivory
+Izzard
+Jackman
+Jacks
+Jackson
+Jacob
+Jacobs
+Jacobson
+Jacques
+Jaffray
+Jagger
+Jakeman
+James
+Jameson
+Jamieson
+Janes
+Jansen
+Jardine
+Jarman
+Jarram
+Jarratt
+Jarrett
+Jarrold
+Jarvis
+Jasper
+Jebson
+Jeffcock
+Jefferies
+Jeffers
+Jefferson
+Jeffery
+Jefford
+Jeffrey
+Jeffreys
+Jeffries
+Jeffs
+Jems
+Jenas
+Jenkin
+Jenkins
+Jenkinson
+Jenks
+Jenkyns
+Jenner
+Jennings
+Jennison
+Jennson
+Jensen
+Jepson
+Jermy
+Jerome
+Jerry
+Jervis
+Jesson
+Jessop
+Jevons
+Jewell
+Jewers
+Jewett
+Jewitt
+Jewkes
+Jewson
+Jiggens
+Jobson
+Johannson
+Johansen
+Johanson
+John
+Johns
+Johnson
+Johnston
+Johnstone
+Jolley
+Jolly
+Jonas
+Jones
+Jonhson
+Jopson
+Jordan
+Jordison
+Jordon
+Joseph
+Joss
+Jourdan
+Jowett
+Jowitt
+Joyce
+Joynson
+Jubb
+Judd
+Judge
+Jukes
+Jupp
+Jury
+Kacy
+Kaddour
+Kamara
+Kampfner
+Kane
+Kanes
+Kapoor
+Karim
+Karne
+Karras
+Kassell
+Kaufman
+Kaul
+Kaur
+Kavanagh
+Kay
+Kaye
+Kayes
+Keable
+Keal
+Kealey
+Keane
+Kearney
+Kearns
+Kearsley
+Kearton
+Keating
+Keaveney
+Keay
+Keeble
+Keefe
+Keegan
+Keelan
+Keeler
+Keeley
+Keeling
+Keenan
+Keene
+Keetley
+Keffler
+Kehoe
+Keighley
+Keight
+Keilty
+Keir
+Keith
+Kelk
+Kell
+Kelland
+Kellems
+Kellie
+Kelliher
+Kelly
+Kelsall
+Kelsey
+Kelso
+Kemp
+Kempson
+Kempster
+Kendall
+Kendell
+Kendrick
+Kenley
+Kennard
+Kennedy
+Kenneford
+Kennell
+Kenneth
+Kennett
+Kenney
+Kenning
+Kenny
+Kenrick
+Kensington
+Kent
+Kentwood
+Kenward
+Kenworthy
+Kenyon
+Keogh
+Kerby
+Kernick
+Kerr
+Kerrell
+Kerridge
+Kerrigan
+Kerrighen
+Kerrison
+Kershaw
+Ketley
+Kett
+Kettell
+Ketteringham
+Kettlewell
+Keward
+Kewley
+Keys
+Keyte
+Keywood
+Khalid
+Khalifa
+Khalil
+Khan
+Kibblewhite
+Kidd
+Kiddle
+Kidman
+Kidner
+Kiely
+Kiernan
+Kilb
+Kilbee
+Kilbey
+Kilbride
+Kilburn
+Kilford
+Kill
+Killeen
+Killen
+Killick
+Killock
+Kilminster
+Kilmurry
+Kilnan
+Kilner
+Kilroy
+Kilshaw
+Kimber
+Kimble
+Kinch
+Kinchin
+Kinder
+King
+Kingdon
+Kinghorn
+Kingman
+Kings
+Kingscott
+Kingsley
+Kingston
+Kinnaird
+Kinnear
+Kinnersley
+Kinniburgh
+Kinnison
+Kinrade
+Kinsella
+Kinsey
+Kinsley
+Kipling
+Kirby
+Kirk
+Kirkbride
+Kirkbright
+Kirkby
+Kirkland
+Kirkman
+Kirkpatrick
+Kirkwood
+Kirtley
+Kirwan
+Kirwin
+Kitchen
+Kitchin
+Kitching
+Kitson
+Kitt
+Klam
+Klein
+Knab
+Knappett
+Knibb
+Knigge
+Knight
+Knightley
+Knighton
+Knights
+Knott
+Knowler
+Knowles
+Knox
+Knoxville
+Knuckles
+Knutt
+Koban
+Kolt
+Kone
+Kore
+Kouma
+Kram
+Kreyling
+Kristensen
+Kromberg
+Kruger
+Kumar
+Kurian
+Kurray
+Kydd
+Kyle
+Kysel
+Labbe
+Lacey
+Lacy
+Laing
+Laird
+Lake
+Lakey
+Lakin
+Lamb
+Lambert
+Lambton
+Lame
+Lamond
+Lancaster
+Lander
+Lane
+Lang
+Langdon
+Lange
+Langford
+Langley
+Langridge
+Langston
+Langton
+Lanham
+Laraway
+Large
+Larkin
+Larkings
+Larsen
+Larsson
+Last
+Latham
+Lathan
+Lathey
+Lattimore
+Laurie
+Laver
+Laverick
+Lavery
+Lawal
+Lawler
+Lawlor
+Lawn
+Lawrance
+Lawrence
+Lawrie
+Laws
+Lawson
+Lawther
+Lawton
+Laycock
+Layton
+Le tissier
+Leach
+Leadley
+Leahy
+Leake
+Leal
+Leary
+Leaver
+Leck
+Leckie
+Ledger
+Lee
+Leech
+Leedham
+Leek
+Leeming
+Lees
+Leese
+Leeson
+Legg
+Legge
+Leggett
+Leigh
+Leighton
+Leitch
+Leith
+Lendon
+Lenihan
+Lennard
+Lennon
+Lennox
+Leonard
+Leroy
+Leslie
+Lester
+Lethbridge
+Levann
+Levett
+Levin
+Levine
+Levy
+Lewin
+Lewington
+Lewins
+Lewis
+Lewry
+Leyland
+Leys
+Leyshon
+Liddell
+Liddle
+Lightfoot
+Lilley
+Lilly
+Lilwall
+Lincoln
+Lind
+Linden
+Lindo
+Lindop
+Lindsay
+Line
+Lines
+Linford
+Ling
+Linley
+Linsby
+Linton
+Lister
+Litchfield
+Little
+Littlewood
+Livermore
+Livingstone
+Llewellyn
+Lloyd
+Loat
+Lobb
+Lock
+Locke
+Lockett
+Lockhart
+Lockie
+Lockwood
+Lockyer
+Lodge
+Loft
+Lofthouse
+Loftus
+Logan
+Lohan
+Lois
+Lomas
+Lomax
+London
+Long
+Longhurst
+Longley
+Longworth
+Lonsdale
+Lopes
+Lopez
+Lord
+Loudon
+Loughran
+Louth
+Lovatt
+Love
+Lovegrove
+Lovell
+Lovelock
+Lovett
+Lovey
+Lowbridge
+Lowdon
+Lowe
+Lowes
+Lowis
+Lowndes
+Lowrie
+Lowry
+Lucas
+Luce
+Lucey
+Luckhurst
+Ludgrove
+Ludkin
+Ludlow
+Luke
+Luker
+Lumb
+Lumley
+Lumsden
+Lunn
+Lunt
+Luscombe
+Luttrell
+Luxton
+Lyall
+Lyes
+Lyme
+Lynas
+Lynch
+Lynes
+Lynn
+Lyon
+Lyons
+Mac
+Macarthur
+Macaulay
+Macdonald
+Mace
+Macfarlane
+Macgregor
+Machin
+Macintyre
+Mack
+Mackay
+Mackenzie
+Mackie
+Maclean
+Macleod
+Macmillan
+Macpherson
+Macrae
+Madden
+Maddocks
+Magee
+Maguire
+Maher
+Mahoney
+Main
+Mair
+Major
+Makin
+Malley
+Mallinson
+Malone
+Maloney
+Mangnall
+Mann
+Manning
+Mansell
+Mansfield
+Manson
+Markham
+Marks
+Marlow
+Marr
+Marriott
+Marsden
+Marsh
+Marshall
+Martin
+Martinez
+Martins
+Mason
+Masters
+Mather
+Mathers
+Matheson
+Mathews
+Matthams
+Matthews
+Maughan
+Mawson
+Maxwell
+May
+Maynard
+Mcarthur
+Mcauley
+Mcavoy
+Mcbain
+Mccabe
+Mccaffrey
+Mccall
+Mccallum
+Mccann
+Mccarthy
+Mccartney
+Mccluskey
+Mcclymont
+Mcconnell
+Mccormack
+Mccormick
+Mccourt
+Mcculloch
+Mccullough
+Mcdermott
+Mcdonagh
+Mcdonald
+Mcdonnell
+Mcdougall
+Mcelroy
+Mcewan
+Mcfadden
+Mcfarlane
+Mcgee
+Mcghee
+Mcgill
+Mcginty
+Mcgowan
+Mcgrady
+Mcgrath
+Mcgregor
+Mcgrory
+Mcguinness
+Mcguire
+Mcintosh
+Mcintyre
+Mckay
+Mckee
+Mckenna
+Mckenzie
+Mckeown
+Mckie
+Mclaren
+Mclaughlin
+Mclean
+Mclellan
+Mcleod
+Mcloughlin
+Mcmahon
+Mcmanus
+Mcmillan
+Mcnally
+Mcnamara
+Mcnaught
+Mcneil
+Mcneill
+Mcnulty
+Mcphail
+Mcphee
+Mcpherson
+Mcrae
+Mcshane
+Mctaggart
+Meadows
+Meakin
+Mears
+Melia
+Mellor
+Meredith
+Merritt
+Metcalf
+Metcalfe
+Michael
+Michel
+Middleton
+Miles
+Milford
+Mill
+Millar
+Millard
+Miller
+Millett
+Milligan
+Millington
+Mills
+Millward
+Milne
+Milner
+Milward
+Mistry
+Mitchell
+Moffat
+Mohamed
+Mohammed
+Molloy
+Molyneux
+Monaghan
+Montague
+Montgomery
+Moody
+Moon
+Mooney
+Moore
+Moorhouse
+Moran
+More
+Moreno
+Moreton
+Morgan
+Moriarty
+Morley
+Moroney
+Morris
+Morrison
+Morrow
+Mortimer
+Morton
+Moseley
+Moss
+Mottram
+Mould
+Muir
+Mullen
+Mulligan
+Mullins
+Mundy
+Munro
+Murphy
+Murray
+Murrell
+Mustafa
+Myatt
+Myers
+Nair
+Nairn
+Nandi
+Nanson
+Nanton
+Napier
+Napper
+Nartey
+Nash
+Nason
+Naughton
+Naumann
+Nayler
+Naylor
+Naysmith
+Neal
+Neale
+Neary
+Neave
+Neaverson
+Nedd
+Needham
+Neeson
+Negros
+Neighbour
+Neill
+Neilsen
+Neilson
+Neish
+Nelmes
+Nelms
+Nelson
+Nemeth
+Nero
+Nesbitt
+Ness
+Nessbert
+Nettleton
+Neville
+Nevins
+Nevis
+Newall
+Newberry
+Newbold
+Newbury
+Newby
+Newcombe
+Newell
+Newey
+Newham
+Newill
+Newington
+Newland
+Newlands
+Newman
+Newsham
+Newsome
+Newson
+Newstead
+Newton
+Neyland
+Nichol
+Nicholas
+Nicholl
+Nicholls
+Nichols
+Nicholson
+Nickel
+Nickolls
+Nicks
+Nicol
+Nicolas
+Nicoll
+Nicolson
+Nield
+Nielsen
+Nielson
+Nightingale
+Niles
+Nilsen
+Nineham
+Nisbet
+Nixon
+Noach
+Noakes
+Nobbs
+Noble
+Noggins
+Nokes
+Nolan
+Nood
+Noon
+Noonan
+Norbert
+Norburn
+Norbury
+Norcross
+Nord
+Norgate
+Norgrove
+Norm
+Norman
+Normington
+Norris
+Norsworthy
+North
+Northcott
+Norton
+Norville
+Norwood
+Notman
+Nott
+Nourse
+Nova
+Nowak
+Nowell
+Noyce
+Noyes
+Nugent
+Number
+Nunn
+Nurse
+Nurton
+Nutella
+Nutman
+Nutt
+Nuttall
+Oakes
+Oakey
+Oakley
+Oaks
+Oakton
+Oates
+Oatridge
+Oatway
+Obrien
+Ocallaghan
+Oconnell
+Oconnor
+Odam
+Oddie
+Oddy
+Odea
+Odell
+Odling
+Odonnell
+Odonoghue
+Odriscoll
+Oflynn
+Ogden
+Ogilvie
+Ogilvy
+Ogrady
+Ohalloran
+Ohara
+Okeefe
+Okey
+Okten
+Olan
+Oldfield
+Oldham
+Olding
+Oldland
+Oldroyd
+Olds
+Oleary
+Oliver
+Olivier
+Ollerhead
+Olley
+Oloughlin
+Olsen
+Olson
+Omalley
+Oman
+Oneil
+Oneill
+Opayne
+Openshaw
+Oram
+Orbell
+Orchard
+Oreilly
+Oriley
+Orman
+Orme
+Ormiston
+Ormond
+Ormsby
+Ormston
+Orrell
+Orritt
+Orton
+Orvis
+Orwin
+Osborn
+Osborne
+Osman
+Osmond
+Ostcliffe
+Ostler
+Osullivan
+Oswald
+Otoole
+Otten
+Otter
+Ottey
+Ottley
+Otton
+Ould
+Oulton
+Overall
+Overett
+Overfield
+Overing
+Overson
+Overton
+Owen
+Owens
+Owings
+Oxby
+Oxenham
+Oxley
+Oxtoby
+Pack
+Packard
+Packer
+Pagan
+Page
+Paige
+Pailing
+Paine
+Painter
+Paisley
+Palfrey
+Palfreyman
+Palin
+Pallett
+Palmer
+Panesar
+Pankhurst
+Pannell
+Parish
+Park
+Parker
+Parkes
+Parkin
+Parkins
+Parkinson
+Parks
+Parmar
+Parnaby
+Parnell
+Parr
+Parratt
+Parrott
+Parry
+Parsons
+Partington
+Partlett
+Partridge
+Pascoe
+Pasfield
+Paskell
+Passmore
+Patchett
+Patel
+Pateman
+Paterson
+Paton
+Patrick
+Patten
+Patterson
+Pattinson
+Pattison
+Patton
+Paul
+Pavot
+Pawson
+Payne
+Peace
+Peach
+Peacock
+Peake
+Peal
+Peaper
+Pearce
+Pears
+Pearson
+Peat
+Peck
+Pedley
+Peebles
+Peel
+Peers
+Pegg
+Peigne
+Pell
+Pelling
+Pemberton
+Pender
+Pendlebury
+Pendleton
+Penfold
+Penn
+Pennell
+Penney
+Pennington
+Percival
+Pereira
+Perez
+Perkin
+Perkins
+Perks
+Perowne
+Perrett
+Perrin
+Perrins
+Perry
+Peters
+Petersen
+Peterson
+Petrova
+Pett
+Petticrew
+Peyton
+Phelan
+Phelps
+Philip
+Philips
+Phillips
+Philpott
+Phipps
+Phoenix
+Pick
+Pickard
+Pickering
+Pickersgill
+Pickett
+Pickford
+Pickthall
+Picot
+Pierce
+Piercey
+Pierre
+Pigott
+Pike
+Pilkington
+Pillay
+Pinder
+Pine
+Pinkney
+Pinner
+Pinnock
+Pinsmail
+Pipe
+Piper
+Pitcher
+Pitchford
+Pitt
+Pitts
+Plant
+Plastow
+Platt
+Platts
+Pledger
+Plouvin
+Plumb
+Plummer
+Pocock
+Pointer
+Pole
+Pollard
+Pollock
+Polson
+Pomeroy
+Pomphrey
+Pond
+Pooke
+Poole
+Poon
+Pope
+Porter
+Potter
+Potts
+Poulter
+Poulton
+Pounder
+Povey
+Powell
+Power
+Powers
+Powis
+Powles
+Poyser
+Pratt
+Preece
+Prendergast
+Prentice
+Prescott
+Preston
+Prevost
+Price
+Prime
+Prince
+Pringle
+Prior
+Pritchard
+Privett
+Probert
+Procter
+Proctor
+Prosser
+Provan
+Pryor
+Pugh
+Pullen
+Purcell
+Purkis
+Purnell
+Purse
+Purvis
+Putt
+Pyle
+Quigley
+Quinlivan
+Quinn
+Quinnell
+Quinton
+Quirk
+Quirke
+Rackham
+Radcliffe
+Radford
+Radley
+Raeburn
+Rafferty
+Rahman
+Raine
+Rainey
+Rainford
+Ralph
+Ralston
+Ramm
+Rampling
+Ramsay
+Ramsden
+Ramsey
+Rand
+Randall
+Randle
+Ranger
+Rankin
+Ranks
+Rann
+Ransom
+Ranson
+Rapson
+Rashid
+Ratcliffe
+Raval
+Raven
+Ravenscroft
+Rawlings
+Rawlinson
+Rawsthorne
+Raymond
+Rayner
+Read
+Reade
+Reader
+Reading
+Readle
+Readman
+Reardon
+Reasbeck
+Reay
+Redden
+Redding
+Reddy
+Redfern
+Redhead
+Redin
+Redman
+Redmond
+Redwood
+Reed
+Rees
+Reese
+Reeve
+Reeves
+Regan
+Regent
+Rehman
+Reid
+Reilly
+Reisser
+Render
+Renna
+Rennalls
+Rennie
+Renshaw
+Renwick
+Reveley
+Reyes
+Reygan
+Reynolds
+Rhoades
+Rhodes
+Rhys
+Ricci
+Rice
+Rich
+Richards
+Richardson
+Riches
+Richman
+Richmond
+Richter
+Rick
+Rickard
+Rickards
+Rickett
+Ricketts
+Riddell
+Riddle
+Riddler
+Ridge
+Ridgway
+Ridgwell
+Ridle
+Ridley
+Rigby
+Rigg
+Rigley
+Riley
+Ring
+Ripley
+Rippin
+Riseborough
+Ritchie
+Rivers
+Rixon
+Roach
+Robb
+Robbins
+Robe
+Robert
+Roberts
+Robertson
+Robin
+Robins
+Robinson
+Robishaw
+Robotham
+Robson
+Roche
+Rochford
+Rockliffe
+Rodden
+Roden
+Rodger
+Rodgers
+Rodham
+Rodrigues
+Rodriguez
+Rodwell
+Roebuck
+Roff
+Roffey
+Rogan
+Rogers
+Rogerson
+Roles
+Rolfe
+Rollinson
+Roman
+Romans
+Ronald
+Ronflard
+Rook
+Rooke
+Roome
+Rooney
+Rootham
+Roper
+Ropple
+Roscoe
+Rose
+Rosenblatt
+Rosenbloom
+Ross
+Rosser
+Rossi
+Rosso
+Roth
+Rothery
+Rothwell
+Rouse
+Roussel
+Rousset
+Routledge
+Rowan
+Rowe
+Rowland
+Rowlands
+Rowley
+Rowlinson
+Rowson
+Royall
+Royle
+Rudd
+Ruff
+Rugg
+Rumbold
+Rumsey
+Ruscoe
+Rush
+Rushbrooke
+Rushby
+Rushton
+Russel
+Russell
+Russon
+Rust
+Rutherford
+Rutter
+Ryan
+Ryans
+Rycroft
+Ryder
+Sadiq
+Sadler
+Said
+Saleh
+Salisbury
+Sallis
+Salmon
+Salt
+Salter
+Sampson
+Samuel
+Samuels
+Sanchez
+Sanders
+Sanderson
+Sandison
+Sands
+Santos
+Sargent
+Saunders
+Savage
+Saville
+Sawyer
+Saxton
+Sayers
+Schmid
+Schmidt
+Schofield
+Scott
+Searle
+Seddon
+Seer
+Selby
+Sellars
+Sellers
+Senior
+Sewell
+Sexton
+Seymour
+Shackleton
+Shah
+Shakespeare
+Shand
+Shanks
+Shannon
+Sharkey
+Sharma
+Sharp
+Sharpe
+Sharples
+Shaughnessy
+Shaw
+Shea
+Shearer
+Sheehan
+Sheldon
+Shelton
+Shepherd
+Sheppard
+Sheridan
+Sherman
+Sherriff
+Sherry
+Sherwood
+Shields
+Shipley
+Short
+Shotton
+Showell
+Shuttleworth
+Silcock
+Silva
+Simmonds
+Simmons
+Simms
+Simon
+Simons
+Simpson
+Sims
+Sinclair
+Singh
+Singleton
+Sinha
+Sisson
+Sissons
+Skelly
+Skelton
+Skinner
+Skipper
+Slade
+Slater
+Slattery
+Sloan
+Slocombe
+Small
+Smallwood
+Smart
+Smit
+Smith
+Smithson
+Smullen
+Smyth
+Smythe
+Sneddon
+Snell
+Snelling
+Snow
+Snowden
+Snowdon
+Somerville
+South
+Southern
+Southgate
+Southwick
+Sparkes
+Sparrow
+Spears
+Speed
+Speight
+Spence
+Spencer
+Spicer
+Spiller
+Spinks
+Spooner
+Squire
+Squires
+Stacey
+Stack
+Staff
+Stafford
+Stainton
+Stamp
+Stanfield
+Stanford
+Stanley
+Stannard
+Stanton
+Stark
+Steadman
+Stedman
+Steel
+Steele
+Steer
+Steere
+Stenhouse
+Stephen
+Stephens
+Stephenson
+Sterling
+Stevens
+Stevenson
+Steward
+Stewart
+Stock
+Stocker
+Stockley
+Stoddart
+Stokes
+Stokoe
+Stone
+Stoppard
+Storer
+Storey
+Storr
+Stott
+Stout
+Strachan
+Strange
+Street
+Stretton
+Strickland
+Stringer
+Strong
+Stroud
+Stuart
+Stubbs
+Stuckey
+Sturgess
+Sturrock
+Styles
+Sugden
+Sullivan
+Summers
+Sumner
+Sunderland
+Sutherland
+Sutton
+Swain
+Swales
+Swan
+Swann
+Swanson
+Sweeney
+Sweeting
+Swift
+Sykes
+Sylvester
+Symes
+Symonds
+Taggart
+Tailor
+Tait
+Talbot
+Tallett
+Tamber
+Tang
+Tanner
+Tansey
+Tansley
+Tappin
+Tapping
+Tapscott
+Tarr
+Tarrant
+Tasker
+Tate
+Tatlock
+Tatlow
+Tatnell
+Taurel
+Tayler
+Taylor
+Teague
+Teal
+Teale
+Teasdale
+Tedd
+Telford
+Tell
+Tellis
+Tempest
+Templar
+Temple
+Templeman
+Templeton
+Tennant
+Terry
+Thackeray
+Thackray
+Thake
+Thatcher
+Thelwell
+Thirlwall
+Thirlway
+Thirlwell
+Thistlethwaite
+Thom
+Thomas
+Thomason
+Thompson
+Thoms
+Thomson
+Thonon
+Thorley
+Thorndyke
+Thorne
+Thornes
+Thornhill
+Thornley
+Thornton
+Thorp
+Thorpe
+Thurbon
+Thurgood
+Thurling
+Thurlow
+Thurman
+Thurston
+Tickner
+Tidmarsh
+Tierney
+Till
+Tillett
+Tilley
+Tilson
+Tilston
+Timberlake
+Timmins
+Timms
+Timney
+Timson
+Tindall
+Tindell
+Tinker
+Tinkler
+Tinsley
+Tipping
+Tippins
+Tips
+Tisdall
+Titmarsh
+Titmus
+Titmuss
+Titterington
+Toal
+Tobin
+Tocher
+Todd
+Tohill
+Toland
+Tolley
+Tollis
+Tolmay
+Tomas
+Tombs
+Tomes
+Tomkins
+Tomlin
+Tomlinson
+Tompkin
+Tompkins
+Toms
+Tong
+Tonge
+Tonks
+Tonner
+Toomer
+Toomey
+Topham
+Topley
+Topliss
+Topp
+Torney
+Torrance
+Torrens
+Torres
+Tosh
+Totten
+Toucet
+Tovar
+Tovey
+Towell
+Towers
+Towle
+Townend
+Towns
+Townsend
+Townsley
+Tozer
+Trafford
+Train
+Trainor
+Trattles
+Travers
+Travill
+Travis
+Traynor
+Treble
+Trennery
+Trent
+Treseder
+Trevor
+Trew
+Trickett
+Trigg
+Trimble
+Trinder
+Trollope
+Troon
+Trotman
+Trott
+Trueman
+Truman
+Trump
+Truscott
+Tuck
+Tucker
+Tuckey
+Tudor
+Tuffnell
+Tufnall
+Tugwell
+Tully
+Tunks
+Tunstall
+Turford
+Turke
+Turkington
+Turland
+Turnbull
+Turner
+Turney
+Turnham
+Turnock
+Turrell
+Turton
+Turvey
+Tuthill
+Tuttle
+Tutton
+Tweddle
+Twigg
+Twiggs
+Twine
+Tyler
+Tyman
+Tyne
+Tyrer
+Tyrrell
+Uddin
+Ullman
+Ullmann
+Ulyatt
+Umney
+Underdown
+Underhill
+Underwood
+Unsworth
+Unwin
+Upfield
+Upjohn
+Upsdell
+Upson
+Upton
+Urwin
+Utley
+Utterson
+Uttley
+Utton
+Uttridge
+Vale
+Valentine
+Vallance
+Vallins
+Vallory
+Valmary
+Vancoller
+Vane
+Vann
+Vanstone
+Vanwell
+Vardy
+Varey
+Varley
+Varndell
+Vass
+Vaughan
+Vaughn
+Veale
+Veasey
+Veevers
+Veitch
+Velds
+Venables
+Ventura
+Verdon
+Verell
+Verney
+Vernon
+Vicary
+Vicens
+Vickars
+Vickerman
+Vickers
+Vickery
+Victor
+Vikers
+Villiger
+Villis
+Vince
+Vincent
+Vine
+Viner
+Vines
+Viney
+Vinicombe
+Vinny
+Vinton
+Virgo
+Voakes
+Vockins
+Vodden
+Vollans
+Voyse
+Vyner
+Wade
+Wadham
+Waghorn
+Wagstaff
+Wain
+Wainwright
+Waite
+Wakefield
+Wakeford
+Wakeham
+Wakelin
+Waldron
+Wale
+Wales
+Walkden
+Walker
+Wall
+Wallace
+Waller
+Walling
+Wallis
+Walls
+Walmsley
+Walpole
+Walsh
+Walshe
+Walter
+Walters
+Walton
+Wane
+Wang
+Warburton
+Warby
+Ward
+Warden
+Wardle
+Ware
+Wareing
+Waring
+Warn
+Warner
+Warren
+Warriner
+Warrington
+Warwick
+Water
+Waterfield
+Waterhouse
+Wateridge
+Waterman
+Waters
+Waterson
+Watkins
+Watkinson
+Watling
+Watson
+Watt
+Watters
+Watts
+Waugh
+Wears
+Weasley
+Weaver
+Webb
+Webber
+Webster
+Weeks
+Weir
+Welch
+Weldon
+Weller
+Wellington
+Wellman
+Wells
+Welsh
+Welton
+Were
+Werner
+Werrett
+West
+Western
+Westgate
+Westlake
+Weston
+Westwell
+Westwood
+Whalley
+Wharton
+Wheatcroft
+Wheatley
+Wheeldon
+Wheeler
+Whelan
+Whitaker
+Whitby
+White
+Whiteford
+Whitehead
+Whitehouse
+Whitelaw
+Whiteley
+Whitfield
+Whitham
+Whiting
+Whitley
+Whitlock
+Whitmore
+Whittaker
+Whittingham
+Whittington
+Whittle
+Whittley
+Whitworth
+Whyte
+Wickens
+Wickham
+Wicks
+Widdows
+Widdowson
+Wiggins
+Wigley
+Wilcox
+Wild
+Wilde
+Wildman
+Wileman
+Wiles
+Wilkes
+Wilkie
+Wilkin
+Wilkins
+Wilkinson
+Wilks
+Wilkshire
+Will
+Willett
+Willetts
+Williams
+Williamson
+Willis
+Wills
+Willson
+Wilmot
+Wilson
+Wilton
+Wiltshire
+Winder
+Windsor
+Winfer
+Winfield
+Winman
+Winn
+Winship
+Winstanley
+Winter
+Wintersgill
+Winward
+Wise
+Wiseman
+Wither
+Withers
+Wolf
+Wolfe
+Wolstencroft
+Wong
+Wood
+Woodcock
+Woodford
+Woodhall
+Woodham
+Woodhams
+Woodhead
+Woodhouse
+Woodland
+Woodley
+Woods
+Woodward
+Wooldridge
+Woollard
+Woolley
+Woolnough
+Wootton
+Worgan
+Wormald
+Worrall
+Worsnop
+Worth
+Worthington
+Wotherspoon
+Wragg
+Wraight
+Wray
+ren
+Wrench
+Wrenn
+Wrigglesworth
+Wright
+Wrightson
+Wyatt
+Wyer
+Yabsley
+Yallop
+Yang
+Yapp
+Yard
+Yardley
+Yarker
+Yarlett
+Yarnall
+Yarnold
+Yarwood
+Yasmin
+Yates
+Yeadon
+Yeardley
+Yeardsley
+Yeates
+Yeatman
+Yeldon
+Yeoman
+Yeomans
+Yetman
+Yeung
+Yoman
+Yomkins
+York
+Yorke
+Yorston
+Youlden
+Young
+Younge
+Younis
+Youssouf
+Yule
+Yusuf
+Zaoui
diff --git a/src/neuralnetwork/generate_alphabets.py b/src/neuralnetwork/generate_alphabets.py
new file mode 100644
index 0000000..0b1e18e
--- /dev/null
+++ b/src/neuralnetwork/generate_alphabets.py
@@ -0,0 +1,44 @@
+import training
+import os
+import sys
+
+if __name__ == "__main__":
+
+ # List all the directories containing country datasets to populate the countries dictionary
+ countries = training.get_countries()
+
+ for c, country in countries.items():
+ print(f"processing {c}...", end="")
+ sys.stdout.flush()
+
+ letters = {}
+
+ # get all the names in a country's dataset
+ all_names = country.get_all()
+
+ # iterate through all letters in the all of the names
+ for name in all_names:
+
+ # preprocess the name
+ name = country.preprocess(name)
+
+ for letter in name:
+ if letter in letters:
+ letters[letter] += 1
+ else:
+ letters[letter] = 1
+
+ print(f" found {len(letters)} in {len(all_names)} names... ", end="")
+ sys.stdout.flush()
+
+ # sort the letters by occurrence
+ letters_sorted = [l for l in letters]
+ letters_sorted.sort()
+ # output sorted letters to a file
+ with open(os.path.join(country.path, "alphabet.txt"), "w") as file:
+ for letter in letters_sorted:
+ file.write(letter)
+ file.write("\n")
+
+ print("saved!")
+ sys.stdout.flush()
diff --git a/src/neuralnetwork/rnn.py b/src/neuralnetwork/rnn.py
new file mode 100644
index 0000000..0662394
--- /dev/null
+++ b/src/neuralnetwork/rnn.py
@@ -0,0 +1,329 @@
+import random
+import time
+import math
+import torch
+import torch.nn as nn
+
+import warnings
+import sys
+
+import copy
+
+from util import AtomicNumber
+
+PRINT_INFORMATION_SECONDS = 2
+num_processes = 12
+
+#ignore warnings
+warnings.filterwarnings('ignore')
+
+
+if "--disable-cuda" in sys.argv:
+ cuda = False
+else:
+ cuda = torch.cuda.is_available()
+
+print(f"CUDA is {'enabled' if cuda else 'disabled'}")
+if cuda:
+ print("CUDA devices:")
+ for device_index in range(torch.cuda.device_count()):
+ print(f"{device_index}|\t{torch.cuda.get_device_name(device_index)}")
+
+device = torch.device("cuda") if cuda else torch.device("cpu")
+
+class RNN(nn.Module):
+ def __init__(self, input_size, hidden_size, output_size):
+ super(RNN, self).__init__()
+ self.hidden_size = hidden_size
+ self.output_size = output_size
+
+ # create the input, hidden and output linear transformation branches
+ self.input_to_hidden = nn.Linear(input_size + hidden_size, hidden_size, device=device)
+ self.input_to_output = nn.Linear(input_size + hidden_size, output_size, device=device)
+ self.output_to_output = nn.Linear(hidden_size + output_size, output_size, device=device)
+
+ # initialise a dropout function to be used on output data
+ self.dropout = nn.Dropout(0.1)
+
+ # initialise the softmax function to be used on output data
+ self.softmax = nn.LogSoftmax(dim=1)
+
+ # do not introduce any randomness by default
+ self.random_factor = 0
+
+
+ def forward(self, inputs, hidden):
+ # combine the input layer with the hidden layer to create the output layer and new hidden layer
+ input_combined = torch.cat((inputs, hidden), 1)
+ hidden = self.input_to_hidden(input_combined)
+ output = self.input_to_output(input_combined)
+ output_combined = torch.cat((hidden, output), 1)
+
+ output = self.output_to_output(output_combined)
+ # apply the functions to the output data
+ output = self.dropout(output)
+ output = self.softmax(output)
+
+ # add noise to the output, based on self.random_factor
+ if self.random_factor > 0:
+ # create a fully random tensor
+ random_tensor = torch.randn(self.output_size)
+ output = torch.add(output, random_tensor, alpha=self.random_factor)
+
+ return output, hidden
+
+ def initHidden(self):
+ # The hidden layer should be tensor with the length that we've specified
+ return torch.zeros(1, self.hidden_size, device=device)
+
+# instantiate the function to use to calculate loss
+# we will use Mean Squared Error between the
+criterion = nn.NLLLoss()
+
+# define the learning rate, to begin with, we can use 0.0005
+learning_rate = 0.0005
+
+"""Train a neural network on a single input name
+ Args:
+ rnn: (RNN) the rnn to train
+ input_tensors: (tensor) The input tensor: a one-hot-encoding from the first letter to the last letter, excluding the end of string marker
+ output_tensors: (tensor) The input tensor: a one-hot-encoding from the second letter to the end of the input data
+ Returns:
+ output: (tensor) the output of the training
+ loss: (float) the loss of the training
+"""
+def train_rnn(rnn, input_tensor, target_tensor):
+ # unsqueeze the target tensor,
+ target_tensor.unsqueeze_(-1)
+
+ # reset the parameters of the neural network
+ hidden = rnn.initHidden()
+ rnn.zero_grad()
+
+ # initiate an float called loss, this will store the error between each iteration output and its target
+ loss = 0
+ for i in range(input_tensor.size(0)):
+ output, hidden = rnn(input_tensor[i], hidden)
+
+ # calculate the error and add it to the overall loss
+ l = criterion(output, target_tensor[i])
+ loss += l
+
+ loss.backward()
+
+ # adjust the parameters of the rnn accordingly
+ for p in rnn.parameters():
+ p.data.add_(-learning_rate, p.grad.data)
+
+ return output, loss.item() / input_tensor.size(0)
+
+"""Create the input tensor for a name, a one hot matrix from the first letter to last letter (excluding EOS)
+ Args:
+ name: (str[]) an array of the letters in the name, can also be supplied as a string literal
+ alphabet: (str[]) The alphabet to use while encoding the name, an array starting with a "NULL" character and ending in an "EOS" character
+ value: (float) (default=1) The value to use for the "1" representing the letter
+ Returns:
+ tensor: (tensor) the input tensor for the given name
+"""
+def input_tensor(name, alphabet, value=1):
+ tensor = torch.zeros(len(name), 1, len(alphabet), device=device)
+
+ #iterate through each letter in the name
+ for li in range(len(name)):
+ letter = name[li]
+ # If the letter isn't in the alphabet, use the first "NULL" character
+ index = alphabet.index(letter) if letter in alphabet else 0
+
+ tensor[li][0][index] = value
+
+ return tensor
+
+"""Create the target tensor for a name, a long tensor from the second letter to the EOS
+ Args:
+ name: (str[]) an array of the letters in the name, can also be supplied as a string literal
+ alphabet: (str[]) The alphabet to use while encoding the name, an array starting with a "NULL" character and ending in an "EOS" character
+ Returns:
+ tensor: (tensor) the input tensor for the given name
+"""
+def target_tensor(name, alphabet):
+ indexes = []
+ for li in range(1, len(name)):
+ letter = name[li]
+ index = alphabet.index(letter) if letter in alphabet else 0
+ indexes.append(index)
+
+ # and add the end of string character
+ indexes.append(len(alphabet) - 1)
+
+ #legacy tensor needs to be made this way
+ if cuda:
+ return torch.cuda.LongTensor(indexes)
+ else:
+ return torch.LongTensor(indexes)
+
+
+"""Train a neural network on a list of names with a given alphabet
+ Args:
+ rnn (RNN): the neural network to train on
+ names: (str[]) the list of names to train on
+ alphabet: (str[]) the alphabet to use to encode characters
+ iterations: (int) (default=10000) The number of iterations of training that should be done
+"""
+def learn_names(rnn, names, alphabet, iterations=100000, num_processes=12):
+
+ # keep track of total time spent training by knowing when we started training
+ start = time.time()
+
+ # define the number of iterations per process
+ iters_per_process = int(iterations/num_processes)
+
+ processes = []
+
+ # keep track of the total loss
+ total_loss = AtomicNumber()
+
+ # keep track of total number of completed iterations
+ completed_iterations = AtomicNumber()
+
+ # keep track of the last time that the information was printed
+ # this way we can print every x seconds
+ last_print = AtomicNumber()
+
+ print(f"Training on {len(names)} names...")
+
+ # spawn processes, each running the _train function
+ torch.multiprocessing.spawn(_train, args=(rnn, names, alphabet, iters_per_process,
+ total_loss, completed_iterations, last_print, start, iterations),
+ nprocs=num_processes,
+ join=True)
+ print()
+
+"""Thread function to use when multiprocessing learn_names
+
+"""
+def _train(rank, rnn, names, alphabet, iterations,
+ total_loss, completed_iterations, last_print,
+ start, total_iterations):
+ for i in range(1, iterations+1):
+ try:
+ # choose a random name to train on
+ name = random.choice(names)
+
+ # create the input and trainint tensors
+ input_name_tensor = input_tensor(name, alphabet)
+ target_name_tensor = target_tensor(name, alphabet)
+
+ # train the rnn on the input and target tensors
+ output, loss = train_rnn(rnn, input_name_tensor, target_name_tensor)
+ total_loss.increment(loss)
+
+ # increment number of completed iterations
+ completed_iterations.increment()
+
+ # to prevent overloading the console, potentially slowing down the training process,
+ # only print information every PRINT_INFORMATION_SECONDS
+ if time.time() - last_print.get() > PRINT_INFORMATION_SECONDS:
+ # set last print to now to prevent other threads from also printing
+ last_print.set(time.time())
+
+ # calculate and display information
+ seconds_elapsed = time.time() - start
+ time_elapsed = "%dm %ds" % (math.floor(seconds_elapsed / 60), seconds_elapsed % 60)
+
+ percentage = completed_iterations.get() / total_iterations * 100
+
+ # print information on the same line as before
+ print("\r%s (%d %d%%) %.4f" % (time_elapsed, completed_iterations.get(), percentage, loss), end="")
+ except:
+ pass
+
+
+"""Sample a random name from the network using a starting letter
+ Args:
+ rnn: (RNN) the neural network to sample from
+ alphabet: (str[]) the alphabet to use to decode the outputs from the network
+ start_letter: (str) the letter to use to start the neural network
+ max_length: (int) (default=50) the maximum length for a name
+ Returns:
+ output_name: (str) the characters that the rnn has generated from the starting letter
+"""
+def sample(rnn, alphabet, start_letter, max_length=50):
+ # disable gradient calculation
+ #with torch.no_grad():
+ # create the input tensor from the start letter, using a randomized value
+ #random_value = random.random()
+ random_value = 1
+ sample_input = input_tensor(start_letter, alphabet, value=random_value)
+
+ rnn.dropout(sample_input)
+
+ # reset hidden layer
+ hidden = rnn.initHidden()
+
+ output_name = [start_letter]
+
+ # use a max length to prevent names from being too long
+ for i in range(max_length):
+ # call the rnn for the next letter
+ output, hidden = rnn(sample_input[0], hidden)
+
+ top_v, top_i = output.topk(1)
+ top_i = top_i[0][0]
+
+ if top_i == len(alphabet)-1: # EOS has been reached
+ break;
+ else:
+ # append next letter to output
+
+ letter = alphabet[top_i]
+ output_name.append(letter)
+
+ sample_input = input_tensor(letter, alphabet)
+
+ return output_name
+
+
+import warnings
+# testing
+if __name__ == "__main__":
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+
+ english_alphabet = [c for c in " abcdefghijklmnopqrstuvwxyz"]
+ english_alphabet.append("") # add the EOS character
+
+
+ option = input("(t)rain or (s)ample?")
+ if option == "t":
+
+ names = []
+ with open("data/datasets/usa/surname.txt", "r") as datafile:
+ # convert all names to lowercase and remove newline character
+ names = [name[:-1].lower() for name in datafile.readlines()]
+
+ # create the neural network with a hidden layer of size 128
+ rnn = RNN(len(english_alphabet), 128, len(english_alphabet))
+
+ # transfer to cuda if cuda is enabled
+ if cuda:
+ rnn.cuda()
+
+ def provide_name():
+ return random.choice(names)
+
+ learn_names(rnn, names, english_alphabet, iterations=100000, num_processes=12)
+ print()
+
+
+ torch.save(rnn, "data/english_names.pt")
+ elif option == "s":
+ rnn = torch.load("data/english_names.pt")
+ if cuda:
+ rnn.cuda()
+ rnn.eval()
+ rnn.random_factor = 0.7
+
+ for start_letter in [i for i in "abcdefghijklmnopqrstuvwxyz"]:
+ print(sample(rnn, english_alphabet, start_letter))
+ else:
+ print("invalid option!")
diff --git a/src/neuralnetwork/training.py b/src/neuralnetwork/training.py
new file mode 100644
index 0000000..85c6dbd
--- /dev/null
+++ b/src/neuralnetwork/training.py
@@ -0,0 +1,373 @@
+import os
+import types
+import json
+import random
+
+from util import *
+from rnn import *
+
+cuda = False
+num_processes = 12
+
+
+class Country:
+ def __init__(self, path):
+ self.path = path
+ self.datasets = {
+ "female": os.path.join(path, "female.txt"),
+ "male": os.path.join(path, "male.txt"),
+ "surname": os.path.join(path, "surname.txt"),
+ }
+
+ # initialise the pre and post proccess function lists
+ self.pre_process = []
+ self.post_process = []
+
+ # load the data file
+ self.load_data()
+
+ # load the alphabet file
+ self.alphabet = self.load_alphabet()
+
+ # initialise the rnn models
+ hidden_size = 128
+ self.rnn = {}
+
+ for dataset in self.datasets:
+ self.rnn[dataset] = RNN(
+ len(self.alphabet), hidden_size, len(self.alphabet))
+
+ """ Load the alphabet from the alphabet file
+ Returns:
+ alphabet: (str[]) the list of the letters/characters to use while training
+ """
+
+ def load_alphabet(self):
+ alphabet_path = os.path.join(self.path, "alphabet.txt")
+
+ # check if the alphabet file exists, if not, raise an exception
+ if os.path.exists(alphabet_path):
+ with open(alphabet_path, "r") as alphabet_file:
+ # Split the file by lines: on letter/character should be on each line
+ letters = alphabet_file.read().split("\n")
+ return letters
+ else:
+ raise Exception(
+ f"The alphabet file {alphabet_path} could not be found")
+ return []
+
+ """ load the data from the data file
+ """
+
+ def load_data(self):
+ data_path = os.path.join(self.path, "data.json")
+ if os.path.exists(data_path):
+ with open(data_path, "r") as data_file:
+ j = json.loads(data_file.read())
+
+ # match the imported global function with the ones listed in the json file
+ for pre in j["pre"]:
+ if pre in globals():
+ func = globals()[pre]
+
+ # check if the requested object is a function
+ if type(func) is types.FunctionType:
+ self.pre_process.append(func)
+ else:
+ raise Exception(
+ f"The function '{pre}' is not a function")
+ else:
+ # If the function was not loaded, throw an exception
+ raise Exception(
+ f"The function '{pre}' was not loaded or does not exist")
+
+ for post in j["post"]:
+ if post in globals():
+ func = globals()[post]
+
+ # check if the requested object is a function
+ if type(func) is types.FunctionType:
+ self.post_process.append(func)
+ else:
+ raise Exception(
+ f"The function '{post}' is not a function")
+ else:
+ # If the function was not loaded, throw an exception
+ raise Exception(
+ f"The function '{post}' was not loaded or does not exist")
+
+ else:
+ # load the default pre and post processing functions
+ self.pre_process = [uncapitalise]
+ self.post_process = [deserialise, capitalise]
+
+ """ List all the names from a given category file
+ Args:
+ category: (str) the category to select names from
+ Returns:
+ data: (str[]) an array containing all of the names from the given category file
+ """
+
+ def get_names(self, category):
+ with open(self.datasets[category], "r") as datafile:
+ return [name for name in datafile.read().split("\n")]
+
+ """ List all names in all categories
+ Returns:
+ data: (str[]) an array with all of the names in this country's datasets
+ """
+
+ def get_all(self):
+ return [name for k in self.datasets for name in self.get_names(k)]
+
+ """ Pre-process a name for training
+ Args:
+ name: the name loaded from the dataset
+ Returns:
+ name: the name after being processed
+ """
+
+ def postprocess(self, name):
+ for f in self.post_process:
+ name = f(name)
+ return name
+
+ """ Post-process a name after sampling
+ Args:
+ name: the name output from the recurrent neural network
+ Returns:
+ name: the name after being processed
+ """
+
+ def preprocess(self, name):
+ for f in self.pre_process:
+ name = f(name)
+ return name
+
+ """ Train a neural network on the given dataset
+ Args:
+ category: (str) the category to sample training names from
+ """
+
+ def train(self, category):
+ # select the RNN model to be training on
+ rnn = self.rnn[category]
+
+ # load names from that dataset and pre proccess them
+ print("preprocessing names...")
+ names = [self.preprocess(name) for name in self.get_names(category)]
+ print(f"processed {len(names)} names!")
+
+ # calculate optimum number of iterations (using 80% of whole dataset)
+ iters = int(len(names) * 0.8)
+
+ # start training
+ learn_names(rnn, names, self.alphabet, iterations=iters,
+ num_processes=num_processes)
+
+ """ Sample a name from the neural network with a given starting letter
+ Args:
+ category: (str) the category to sample generated names from
+ Returns:
+ name: the output from the neural network
+ """
+
+ def sample(self, category, start_letter):
+
+ # select the RNN model to be sampling from
+ rnn = self.rnn[category]
+
+ # set the random factor of the RNN to randomise names that are generated
+ rnn.random_factor = 0.7
+
+ # call the rnn sample function to generate a single name
+ name = sample(rnn, self.alphabet, start_letter)
+
+ # post process the name and return
+ return self.postprocess(name)
+
+ """ Load the rnn from its file
+ Args:
+ category: (str) the category to load
+ parent_directory: (str) where to find the model
+ """
+
+ def load_rnn(self, category, parent_directory):
+ model_file = os.path.join(parent_directory, f"{category}.pt")
+ self.rnn[category] = torch.load(model_file)
+
+ """ Save the rnn of a given category to its file
+ Args:
+ category: (str) the category to save
+ parent_directory: (str) the directory to save the model file to
+ """
+
+ def save_rnn(self, category, parent_directory):
+ rnn = self.rnn[category]
+ model_file = os.path.join(parent_directory, f"{category}.pt")
+ torch.save(rnn, model_file)
+
+
+def get_countries():
+ return {
+ country: Country(os.path.join(countries_path, country)) for country in os.listdir(countries_path) if os.path.isdir(os.path.join(countries_path, country))
+ }
+
+
+""" train all of the datasets from a specific country
+ Args:
+ country: (Country)
+"""
+
+
+def train_country(country, name):
+ datasets = country.datasets
+ for dataset in datasets:
+ print(f"Training {dataset} in {name}")
+ country.train(dataset)
+
+ print(f"Finished training on {dataset}... saving...", end="")
+ path = os.path.join("data", "models", name)
+
+ # check if the path already exists before trying to make directories
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+ country.save_rnn(dataset, path)
+ print("saved!")
+
+
+def sample_country(country, country_name, number_of_samples=10000):
+
+ datasets = country.datasets
+ for dataset in datasets:
+
+ # ensure that the model exists before sampling
+ path = os.path.join("data", "models", country_name)
+ if os.path.exists(os.path.join(path, dataset + ".pt")):
+
+ # load the country's rnn
+ country.load_rnn(dataset, path)
+
+ # load the names from the country's dataset, and pre-process them
+ names = [country.preprocess(name)
+ for name in country.get_names(dataset)]
+
+ # make a dictionary full of start letters and their frequency
+ start_letters = {}
+
+ for name in names:
+ if len(name) > 0:
+ start_letter = name[0]
+
+ # if the start letter isn't already in the dictionary, add it with value 1
+ if start_letter in start_letters:
+ start_letters[start_letter] += 1
+ else:
+ start_letters[start_letter] = 1
+
+ # turn each integer count into a float where: letter_weight=frequency/total_names
+ total = len(names)
+
+ for letter in start_letters:
+ weight = float(start_letters[letter] / total)
+ start_letters[letter] = weight
+
+ # sample names from the RNN
+ sampled_names = []
+
+ for i in range(number_of_samples):
+ try:
+ letter = weighted_choice(start_letters)
+ sample = country.sample(dataset, letter)
+ sampled_names.append(sample)
+ except:
+ pass
+
+ # remove duplicate names
+ sampled_names = list(dict.fromkeys(sampled_names))
+
+ # create a sqlite connection
+ connection = sqlite3.connect(database)
+
+ # always close the connection when finished
+ with connection:
+ cursor = connection.cursor()
+ for name in sampled_names:
+ sql = "INSERT INTO names(Name, Origin, Category) VALUES(?, ?, ?)"
+
+ # insert the current name and options into the database
+ cursor.execute(sql, (name, country_name, dataset))
+
+ # commit changes and save the database
+ connection.commit()
+
+ print(
+ f"Saved {len(sampled_names)} names for {country_name}/{dataset}")
+
+ else:
+ print(f"the model: {country_name}/{dataset} was not found.")
+
+
+countries_path = "data/datasets"
+database = os.path.join("data", "names.db")
+if __name__ == "__main__":
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+
+ # allow processes on this model to share memory
+ torch.multiprocessing.set_start_method('spawn')
+
+ # List all the directories containing country datasets to populate the countries dictionary
+ countries = get_countries()
+
+ country_count = len(countries)
+ # Display debug information
+ print(f"Loaded {country_count} countries!")
+
+ # list all countries in neat collumns
+ collumns = 4
+ width = 14
+ i = 0
+ for country in countries:
+ i += 1
+
+ # print the country and then its index
+ print(country, end="")
+
+ # organise into rows and collumns
+ if i % collumns == 0:
+ print("")
+ else:
+ # separate collumns with spaces
+ print(" " * (width - len(country)), end="")
+
+ # keep asking until the country selection is valid
+ good_selection = False
+ while not good_selection:
+ # prompt user to select a country to train, or train all
+ country_selection = input(
+ "select the name of a country to train on, or (all) to train on all countries: ")
+
+ good_selection = True
+ selected_countries = []
+
+ # if the user selected all, then add all countries to list, if not, add the selected country
+ if country_selection.lower() == "all":
+ [selected_countries.append(country) for country in countries]
+ elif country_selection.lower() in countries:
+ selected_countries.append(country_selection)
+ else:
+ print("Country not found, try again")
+ good_selection = False
+
+ choice = input("(t)rain on data, or (s)ample from weights?")
+
+ if choice.lower()[0] == "t":
+ for country in selected_countries:
+ train_country(countries[country], country)
+
+ elif choice.lower()[0] == "s":
+ create_table(database)
+ for country in selected_countries:
+ sample_country(countries[country], country)
diff --git a/src/neuralnetwork/util.py b/src/neuralnetwork/util.py
new file mode 100644
index 0000000..268819e
--- /dev/null
+++ b/src/neuralnetwork/util.py
@@ -0,0 +1,185 @@
+import sqlite3
+import tensorflow as tf
+from pincelate import Pincelate
+from multiprocessing import Value
+import random
+
+"""Atomic Number
+A multiprocessing-safe Number that you can increment and set a value to.
+"""
+class AtomicNumber:
+ def __init__(self, initial=0):
+ # set the initial value of the number
+ self._v = Value("d", initial)
+
+ # use python thread locks
+ self._lock = self._v.get_lock()
+
+ def set(self, num):
+ with self._lock:
+ # set the value of the number and return it
+ self._v.value = num
+ return self._v.value
+
+ def increment(self, num=1):
+ with self._lock:
+ # increase the value of the number and then return it
+ self._v.value += num
+ return self._v.value
+
+ def get(self):
+ return self._v.value
+
+
+""" Capitalise the first letter of a name
+ Args:
+ name: (str) the name to transform
+ Returns:
+ name: (str) the output name
+"""
+
+
+def capitalise(name):
+ return str(name).capitalize()
+
+
+""" uncapitalise the first letter of a name
+ Args:
+ name: (str) the name to transform
+ Returns:
+ name: (str) the output name
+"""
+
+
+def uncapitalise(name):
+ return str(name).lower()
+
+
+# import pincelate
+
+# tell tensorflow to only log ERRORS rather than all problems
+tf.get_logger().setLevel('ERROR')
+
+pin = Pincelate()
+
+""" Transliterate names into their phonetic spelling
+ Args:
+ name: (str) the name to transliterate
+ Returns:
+ name: (str) the pronunciation of the name as an arpabet list
+"""
+
+
+def transliterate(name):
+ output = []
+
+ # iterate through each word and sound out separately
+ for word in name.split(" "):
+ try:
+ for phoneme in pin.soundout(word):
+ output.append(phoneme)
+ except Exception as e:
+ output.append(word)
+ output.append(" ")
+
+ # remove the trailing " "
+ output.pop()
+
+ return output
+
+
+""" Transliterate phonetic spellings back into names
+ Args:
+ name: (str) the pronunciation of the name as an arpabet list
+ Returns:
+ name: (str) a guessed spelling of the given phoneme list
+"""
+
+
+def reverse_transliterate(name):
+ words = []
+
+ current_word = []
+ # iterate through all phonemes, spliting groups between " " into words
+ for phoneme in name:
+ if phoneme == " ":
+ words.append(current_word)
+
+ # reset current word
+ current_word = []
+ else:
+ current_word.append(phoneme)
+
+ # add whats left of the current word to the list of words
+ words.append(current_word)
+
+ # spell each word separately
+ spellings = [pin.spell(word) for word in words]
+ return " ".join(spellings)
+
+
+"""Load random line from a given filename
+"""
+
+
+def get_random_line(file_name):
+ total_bytes = os.stat(file_name).st_size
+ random_point = random.randint(0, total_bytes)
+ file = open(file_name)
+ file.seek(random_point)
+ file.readline() # skip this line to clear the partial line
+ return file.readline()
+
+
+""" Concatenate elemnts of a list
+ Args:
+ name: (str[]) the letters of a name in an array
+ Returns:
+ name: (str)
+"""
+
+
+def deserialise(name):
+ return "".join(name)
+
+
+""" return a random item from a dictionary of weighted items
+ Args:
+ weights: (dict) a dictionary containing the items as keys and float values as weights
+ Returns:
+ item: a random item selected from the dictionary
+"""
+
+
+def weighted_choice(weights):
+ # choose a randm number between 0 and 1
+ choice = random.uniform(0.0, 1.0)
+
+ # iterate through weights, subtracting the weight from the choice each time
+ for item, weight in weights.items():
+ choice -= weight
+
+ # if we are currently on the chosen item, return it
+ if choice < 0:
+ return item
+
+ # in case the input dictionary is incorrectly setup, return the last item
+ return list(weights)[-1]
+
+
+def create_table(database_path):
+ # connect to the database and get the cursor
+ connection = sqlite3.connect(database_path)
+
+ # always close the connection at the end
+ with connection:
+ cursor = connection.cursor()
+
+ cursor.execute("CREATE TABLE IF NOT EXISTS names (\
+ Name TEXT,\
+ Origin TEXT,\
+ Category TEXT\
+ )")
+
+ # commit the changes, saving them
+ connection.commit()
diff --git a/src/webserver/dist/index.html b/src/webserver/dist/index.html
new file mode 100644
index 0000000..cd016b2
--- /dev/null
+++ b/src/webserver/dist/index.html
@@ -0,0 +1,122 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Name Generator</title>
+
+ <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
+
+ <script type="text/javascript" src="/site.js"></script>
+ <link rel="stylesheet" href="style.css">
+
+
+</head>
+<body onload="updateMap()">
+ <div class="main">
+ <h1 class="title box-item">Name Generator</h1>
+
+ <div id="namearea" class="box-item">
+ <!-- Area for generated names to show-->
+ </div>
+
+ <button class="box-item" id="generate" onclick="generateName()">Generate Name</button>
+
+ <div class="options box-item">
+ <select id="gender">
+ <option value="male">Male</option>
+ <option value="female">Female</option>
+ </select>
+
+ <select id="origin" onchange="if (this.selectedIndex) updateMap();">
+ <option value="uk">UK</option>
+ <option value="usa">USA</option>
+ <option value="taiwan">Taiwan</option>
+ <option value="switzerland">Switzerland</option>
+ <option value="sweden">Sweden</option>
+ <option value="spain">Spain</option>
+ <option value="south_africa">South Africa</option>
+ <option value="slovenia">Slovenia</option>
+ <option value="singapore">Singapore</option>
+ <option value="serbia">Serbia</option>
+ <option value="russia">Russia</option>
+ <option value="puerto_rico">Puerto Rico</option>
+ <option value="portugal">Portugal</option>
+ <option value="poland">Poland</option>
+ <option value="philpine">Philippines</option>
+ <option value="peru">Peru</option>
+ <option value="panama">Panama</option>
+ <option value="norway">Norway</option>
+ <option value="nigeria">Nigeria</option>
+ <option value="netherland">Netherlands</option>
+ <option value="namibia">Namibia</option>
+ <option value="moldova">Moldova</option>
+ <option value="mexico">Mexico</option>
+ <option value="mauritius">Mauritius</option>
+ <option value="malta">Malta</option>
+ <option value="malaysia">Malaysia</option>
+ <option value="macao">Macao</option>
+ <option value="luxemburj">Luxembourg</option>
+ <option value="lithunia">Lithuania</option>
+ <option value="jamaica">Jamaica</option>
+ <option value="italy">Italy</option>
+ <option value="israel">Israel</option>
+ <option value="ireland">Ireland</option>
+ <option value="iran">Iran</option>
+ <option value="indonesia">Indonesia</option>
+ <option value="india">India</option>
+ <option value="iceland">Iceland</option>
+ <option value="hungary">Hungary</option>
+ <option value="honduras">Honduras</option>
+ <option value="haiti">Haiti</option>
+ <option value="finland">Finland</option>
+ <option value="fiji">Fiji</option>
+ <option value="ethopia">Ethiopia</option>
+ <option value="estonia">Estonia</option>
+ <option value="ecuador">Ecuador</option>
+ <option value="dibouti">Djibouti</option>
+ <option value="denmark">Denmark</option>
+ <option value="czech">Czech</option>
+ <option value="cyprus">Cyprus</option>
+ <option value="croatia">Croatia</option>
+ <option value="costa">Costa Rica</option>
+ <option value="colombia">Colombia</option>
+ <option value="chile">Chile</option>
+ <option value="canada">Canada</option>
+ <option value="cameroon">Cameroon</option>
+ <option value="cambodia">Cambodia</option>
+ <option value="burundi">Burundi</option>
+ <option value="bulgaria">Bulgaria</option>
+ <option value="brunei">Brunei</option>
+ <option value="brazil">Brazil</option>
+ <option value="botswana">Botswana</option>
+ <option value="bangladesh">Bangladesh</option>
+ <option value="azerbaijan">Azerbaijan</option>
+ <option value="austria">Austria</option>
+ <option value="argentina">Argentina</option>
+ <option value="angolia">Angola</option>
+ <option value="albania">Albania</option>
+ <option value="afghanistan">Afghanistan</option>
+ </select>
+ </div>
+
+ <canvas id="worldmap" width="2947" height="1601"></canvas>
+
+
+ <div>
+ <button id="advanced" onclick="toggleAdvanced()">Advanced Options</button>
+ </div>
+
+ <div id="advancedoptions" style="display: none">
+ <p></p>
+ <label>number of names: </label><input id="number" type="number" value="1" min="1" max="99" maxlength="2" onkeyup="forceCount()">
+ <p></p>
+
+ <label>generate surnames: </label><input id="surnames" type="checkbox" checked="true">
+ <span class="indicator" onclick="checkBox(document.getElementById('surnames'))"></span>
+ </input>
+ </div>
+ </div>
+
+
+</body>
+</html>
diff --git a/src/webserver/dist/map/afghanistan.png b/src/webserver/dist/map/afghanistan.png
new file mode 100644
index 0000000..49abc92
--- /dev/null
+++ b/src/webserver/dist/map/afghanistan.png
Binary files differ
diff --git a/src/webserver/dist/map/albania.png b/src/webserver/dist/map/albania.png
new file mode 100644
index 0000000..c045c57
--- /dev/null
+++ b/src/webserver/dist/map/albania.png
Binary files differ
diff --git a/src/webserver/dist/map/angolia.png b/src/webserver/dist/map/angolia.png
new file mode 100644
index 0000000..2e415e5
--- /dev/null
+++ b/src/webserver/dist/map/angolia.png
Binary files differ
diff --git a/src/webserver/dist/map/argentina.png b/src/webserver/dist/map/argentina.png
new file mode 100644
index 0000000..458376c
--- /dev/null
+++ b/src/webserver/dist/map/argentina.png
Binary files differ
diff --git a/src/webserver/dist/map/austria.png b/src/webserver/dist/map/austria.png
new file mode 100644
index 0000000..f3ed00e
--- /dev/null
+++ b/src/webserver/dist/map/austria.png
Binary files differ
diff --git a/src/webserver/dist/map/azerbaijan.png b/src/webserver/dist/map/azerbaijan.png
new file mode 100644
index 0000000..430b9d6
--- /dev/null
+++ b/src/webserver/dist/map/azerbaijan.png
Binary files differ
diff --git a/src/webserver/dist/map/background.png b/src/webserver/dist/map/background.png
new file mode 100644
index 0000000..77802f6
--- /dev/null
+++ b/src/webserver/dist/map/background.png
Binary files differ
diff --git a/src/webserver/dist/map/bangladesh.png b/src/webserver/dist/map/bangladesh.png
new file mode 100644
index 0000000..8fdf65a
--- /dev/null
+++ b/src/webserver/dist/map/bangladesh.png
Binary files differ
diff --git a/src/webserver/dist/map/botswana.png b/src/webserver/dist/map/botswana.png
new file mode 100644
index 0000000..ec58775
--- /dev/null
+++ b/src/webserver/dist/map/botswana.png
Binary files differ
diff --git a/src/webserver/dist/map/brazil.png b/src/webserver/dist/map/brazil.png
new file mode 100644
index 0000000..8ba32c5
--- /dev/null
+++ b/src/webserver/dist/map/brazil.png
Binary files differ
diff --git a/src/webserver/dist/map/brunei.png b/src/webserver/dist/map/brunei.png
new file mode 100644
index 0000000..c518380
--- /dev/null
+++ b/src/webserver/dist/map/brunei.png
Binary files differ
diff --git a/src/webserver/dist/map/bulgaria.png b/src/webserver/dist/map/bulgaria.png
new file mode 100644
index 0000000..c8edece
--- /dev/null
+++ b/src/webserver/dist/map/bulgaria.png
Binary files differ
diff --git a/src/webserver/dist/map/burundi.png b/src/webserver/dist/map/burundi.png
new file mode 100644
index 0000000..3f8d894
--- /dev/null
+++ b/src/webserver/dist/map/burundi.png
Binary files differ
diff --git a/src/webserver/dist/map/cambodia.png b/src/webserver/dist/map/cambodia.png
new file mode 100644
index 0000000..c92c6f3
--- /dev/null
+++ b/src/webserver/dist/map/cambodia.png
Binary files differ
diff --git a/src/webserver/dist/map/cameroon.png b/src/webserver/dist/map/cameroon.png
new file mode 100644
index 0000000..b5b57ea
--- /dev/null
+++ b/src/webserver/dist/map/cameroon.png
Binary files differ
diff --git a/src/webserver/dist/map/canada.png b/src/webserver/dist/map/canada.png
new file mode 100644
index 0000000..7358637
--- /dev/null
+++ b/src/webserver/dist/map/canada.png
Binary files differ
diff --git a/src/webserver/dist/map/chile.png b/src/webserver/dist/map/chile.png
new file mode 100644
index 0000000..e0a3c50
--- /dev/null
+++ b/src/webserver/dist/map/chile.png
Binary files differ
diff --git a/src/webserver/dist/map/colombia.png b/src/webserver/dist/map/colombia.png
new file mode 100644
index 0000000..3859cc0
--- /dev/null
+++ b/src/webserver/dist/map/colombia.png
Binary files differ
diff --git a/src/webserver/dist/map/costa.png b/src/webserver/dist/map/costa.png
new file mode 100644
index 0000000..035badd
--- /dev/null
+++ b/src/webserver/dist/map/costa.png
Binary files differ
diff --git a/src/webserver/dist/map/croatia.png b/src/webserver/dist/map/croatia.png
new file mode 100644
index 0000000..1ce5650
--- /dev/null
+++ b/src/webserver/dist/map/croatia.png
Binary files differ
diff --git a/src/webserver/dist/map/cyprus.png b/src/webserver/dist/map/cyprus.png
new file mode 100644
index 0000000..ea90e2a
--- /dev/null
+++ b/src/webserver/dist/map/cyprus.png
Binary files differ
diff --git a/src/webserver/dist/map/czech.png b/src/webserver/dist/map/czech.png
new file mode 100644
index 0000000..9f89545
--- /dev/null
+++ b/src/webserver/dist/map/czech.png
Binary files differ
diff --git a/src/webserver/dist/map/denmark.png b/src/webserver/dist/map/denmark.png
new file mode 100644
index 0000000..bef926b
--- /dev/null
+++ b/src/webserver/dist/map/denmark.png
Binary files differ
diff --git a/src/webserver/dist/map/dibouti.png b/src/webserver/dist/map/dibouti.png
new file mode 100644
index 0000000..43015e8
--- /dev/null
+++ b/src/webserver/dist/map/dibouti.png
Binary files differ
diff --git a/src/webserver/dist/map/ecuador.png b/src/webserver/dist/map/ecuador.png
new file mode 100644
index 0000000..bf2e9d4
--- /dev/null
+++ b/src/webserver/dist/map/ecuador.png
Binary files differ
diff --git a/src/webserver/dist/map/estonia.png b/src/webserver/dist/map/estonia.png
new file mode 100644
index 0000000..fa6ac33
--- /dev/null
+++ b/src/webserver/dist/map/estonia.png
Binary files differ
diff --git a/src/webserver/dist/map/ethopia.png b/src/webserver/dist/map/ethopia.png
new file mode 100644
index 0000000..207b3e7
--- /dev/null
+++ b/src/webserver/dist/map/ethopia.png
Binary files differ
diff --git a/src/webserver/dist/map/fiji.png b/src/webserver/dist/map/fiji.png
new file mode 100644
index 0000000..b574fc9
--- /dev/null
+++ b/src/webserver/dist/map/fiji.png
Binary files differ
diff --git a/src/webserver/dist/map/finland.png b/src/webserver/dist/map/finland.png
new file mode 100644
index 0000000..1a2754e
--- /dev/null
+++ b/src/webserver/dist/map/finland.png
Binary files differ
diff --git a/src/webserver/dist/map/haiti.png b/src/webserver/dist/map/haiti.png
new file mode 100644
index 0000000..c0773a6
--- /dev/null
+++ b/src/webserver/dist/map/haiti.png
Binary files differ
diff --git a/src/webserver/dist/map/honduras.png b/src/webserver/dist/map/honduras.png
new file mode 100644
index 0000000..fa7442d
--- /dev/null
+++ b/src/webserver/dist/map/honduras.png
Binary files differ
diff --git a/src/webserver/dist/map/hungary.png b/src/webserver/dist/map/hungary.png
new file mode 100644
index 0000000..97d9e91
--- /dev/null
+++ b/src/webserver/dist/map/hungary.png
Binary files differ
diff --git a/src/webserver/dist/map/iceland.png b/src/webserver/dist/map/iceland.png
new file mode 100644
index 0000000..d1f0e7d
--- /dev/null
+++ b/src/webserver/dist/map/iceland.png
Binary files differ
diff --git a/src/webserver/dist/map/india.png b/src/webserver/dist/map/india.png
new file mode 100644
index 0000000..e0fc17b
--- /dev/null
+++ b/src/webserver/dist/map/india.png
Binary files differ
diff --git a/src/webserver/dist/map/indonesia.png b/src/webserver/dist/map/indonesia.png
new file mode 100644
index 0000000..c31bf40
--- /dev/null
+++ b/src/webserver/dist/map/indonesia.png
Binary files differ
diff --git a/src/webserver/dist/map/iran.png b/src/webserver/dist/map/iran.png
new file mode 100644
index 0000000..2ee5b2b
--- /dev/null
+++ b/src/webserver/dist/map/iran.png
Binary files differ
diff --git a/src/webserver/dist/map/ireland.png b/src/webserver/dist/map/ireland.png
new file mode 100644
index 0000000..92fd6dc
--- /dev/null
+++ b/src/webserver/dist/map/ireland.png
Binary files differ
diff --git a/src/webserver/dist/map/israel.png b/src/webserver/dist/map/israel.png
new file mode 100644
index 0000000..3c350f2
--- /dev/null
+++ b/src/webserver/dist/map/israel.png
Binary files differ
diff --git a/src/webserver/dist/map/italy.png b/src/webserver/dist/map/italy.png
new file mode 100644
index 0000000..fb18140
--- /dev/null
+++ b/src/webserver/dist/map/italy.png
Binary files differ
diff --git a/src/webserver/dist/map/jamaica.png b/src/webserver/dist/map/jamaica.png
new file mode 100644
index 0000000..0cc2224
--- /dev/null
+++ b/src/webserver/dist/map/jamaica.png
Binary files differ
diff --git a/src/webserver/dist/map/lithunia.png b/src/webserver/dist/map/lithunia.png
new file mode 100644
index 0000000..633fc4b
--- /dev/null
+++ b/src/webserver/dist/map/lithunia.png
Binary files differ
diff --git a/src/webserver/dist/map/luxemburj.png b/src/webserver/dist/map/luxemburj.png
new file mode 100644
index 0000000..c296bd0
--- /dev/null
+++ b/src/webserver/dist/map/luxemburj.png
Binary files differ
diff --git a/src/webserver/dist/map/macao.png b/src/webserver/dist/map/macao.png
new file mode 100644
index 0000000..8c3017b
--- /dev/null
+++ b/src/webserver/dist/map/macao.png
Binary files differ
diff --git a/src/webserver/dist/map/malaysia.png b/src/webserver/dist/map/malaysia.png
new file mode 100644
index 0000000..7c14b5a
--- /dev/null
+++ b/src/webserver/dist/map/malaysia.png
Binary files differ
diff --git a/src/webserver/dist/map/malta.png b/src/webserver/dist/map/malta.png
new file mode 100644
index 0000000..bdbfc49
--- /dev/null
+++ b/src/webserver/dist/map/malta.png
Binary files differ
diff --git a/src/webserver/dist/map/mauritius.png b/src/webserver/dist/map/mauritius.png
new file mode 100644
index 0000000..6e39be8
--- /dev/null
+++ b/src/webserver/dist/map/mauritius.png
Binary files differ
diff --git a/src/webserver/dist/map/mexico.png b/src/webserver/dist/map/mexico.png
new file mode 100644
index 0000000..ac7d570
--- /dev/null
+++ b/src/webserver/dist/map/mexico.png
Binary files differ
diff --git a/src/webserver/dist/map/moldova.png b/src/webserver/dist/map/moldova.png
new file mode 100644
index 0000000..aea9bb2
--- /dev/null
+++ b/src/webserver/dist/map/moldova.png
Binary files differ
diff --git a/src/webserver/dist/map/namibia.png b/src/webserver/dist/map/namibia.png
new file mode 100644
index 0000000..013eb0c
--- /dev/null
+++ b/src/webserver/dist/map/namibia.png
Binary files differ
diff --git a/src/webserver/dist/map/netherland.png b/src/webserver/dist/map/netherland.png
new file mode 100644
index 0000000..ea929f8
--- /dev/null
+++ b/src/webserver/dist/map/netherland.png
Binary files differ
diff --git a/src/webserver/dist/map/nigeria.png b/src/webserver/dist/map/nigeria.png
new file mode 100644
index 0000000..fbb8c81
--- /dev/null
+++ b/src/webserver/dist/map/nigeria.png
Binary files differ
diff --git a/src/webserver/dist/map/norway.png b/src/webserver/dist/map/norway.png
new file mode 100644
index 0000000..8246c98
--- /dev/null
+++ b/src/webserver/dist/map/norway.png
Binary files differ
diff --git a/src/webserver/dist/map/panama.png b/src/webserver/dist/map/panama.png
new file mode 100644
index 0000000..2a080cb
--- /dev/null
+++ b/src/webserver/dist/map/panama.png
Binary files differ
diff --git a/src/webserver/dist/map/peru.png b/src/webserver/dist/map/peru.png
new file mode 100644
index 0000000..c0c759b
--- /dev/null
+++ b/src/webserver/dist/map/peru.png
Binary files differ
diff --git a/src/webserver/dist/map/philpine.png b/src/webserver/dist/map/philpine.png
new file mode 100644
index 0000000..4301c70
--- /dev/null
+++ b/src/webserver/dist/map/philpine.png
Binary files differ
diff --git a/src/webserver/dist/map/poland.png b/src/webserver/dist/map/poland.png
new file mode 100644
index 0000000..f16d57f
--- /dev/null
+++ b/src/webserver/dist/map/poland.png
Binary files differ
diff --git a/src/webserver/dist/map/portugal.png b/src/webserver/dist/map/portugal.png
new file mode 100644
index 0000000..bdec23d
--- /dev/null
+++ b/src/webserver/dist/map/portugal.png
Binary files differ
diff --git a/src/webserver/dist/map/puerto_rico.png b/src/webserver/dist/map/puerto_rico.png
new file mode 100644
index 0000000..e7c0b10
--- /dev/null
+++ b/src/webserver/dist/map/puerto_rico.png
Binary files differ
diff --git a/src/webserver/dist/map/russia.png b/src/webserver/dist/map/russia.png
new file mode 100644
index 0000000..e77b48f
--- /dev/null
+++ b/src/webserver/dist/map/russia.png
Binary files differ
diff --git a/src/webserver/dist/map/serbia.png b/src/webserver/dist/map/serbia.png
new file mode 100644
index 0000000..c3debe2
--- /dev/null
+++ b/src/webserver/dist/map/serbia.png
Binary files differ
diff --git a/src/webserver/dist/map/singapore.png b/src/webserver/dist/map/singapore.png
new file mode 100644
index 0000000..59e3aec
--- /dev/null
+++ b/src/webserver/dist/map/singapore.png
Binary files differ
diff --git a/src/webserver/dist/map/slovenia.png b/src/webserver/dist/map/slovenia.png
new file mode 100644
index 0000000..1dd5ebf
--- /dev/null
+++ b/src/webserver/dist/map/slovenia.png
Binary files differ
diff --git a/src/webserver/dist/map/south_africa.png b/src/webserver/dist/map/south_africa.png
new file mode 100644
index 0000000..ecdccb7
--- /dev/null
+++ b/src/webserver/dist/map/south_africa.png
Binary files differ
diff --git a/src/webserver/dist/map/spain.png b/src/webserver/dist/map/spain.png
new file mode 100644
index 0000000..b6947e3
--- /dev/null
+++ b/src/webserver/dist/map/spain.png
Binary files differ
diff --git a/src/webserver/dist/map/sweden.png b/src/webserver/dist/map/sweden.png
new file mode 100644
index 0000000..6b7ba10
--- /dev/null
+++ b/src/webserver/dist/map/sweden.png
Binary files differ
diff --git a/src/webserver/dist/map/switzerland.png b/src/webserver/dist/map/switzerland.png
new file mode 100644
index 0000000..6a8180a
--- /dev/null
+++ b/src/webserver/dist/map/switzerland.png
Binary files differ
diff --git a/src/webserver/dist/map/taiwan.png b/src/webserver/dist/map/taiwan.png
new file mode 100644
index 0000000..ca08390
--- /dev/null
+++ b/src/webserver/dist/map/taiwan.png
Binary files differ
diff --git a/src/webserver/dist/map/uk.png b/src/webserver/dist/map/uk.png
new file mode 100644
index 0000000..51f6e4d
--- /dev/null
+++ b/src/webserver/dist/map/uk.png
Binary files differ
diff --git a/src/webserver/dist/map/usa.png b/src/webserver/dist/map/usa.png
new file mode 100644
index 0000000..06cabde
--- /dev/null
+++ b/src/webserver/dist/map/usa.png
Binary files differ
diff --git a/src/webserver/dist/site.js b/src/webserver/dist/site.js
new file mode 100644
index 0000000..2e9bac3
--- /dev/null
+++ b/src/webserver/dist/site.js
@@ -0,0 +1,129 @@
+
+
+// the function to be called when the generate name button is pressed
+function generateName() {
+
+ // get the values of the various buttons and selectors and store them as variables
+ var gender = document.getElementById("gender").value;
+ var origin = document.getElementById("origin").value;
+
+ var count = parseInt(document.getElementById("number").value);
+ var surnames = document.getElementById("surnames").checked;
+
+ // create a request object
+ var request = {
+ "origin": origin,
+ "gender": gender,
+ "count": count,
+ "surname": surnames
+ };
+
+ // turn the request json into a string
+ request = JSON.stringify(request)
+
+ console.log(request)
+
+ // Make the http request using ajax
+ const http = new XMLHttpRequest();
+ const url = "/api/name";
+ http.open("POST", url);
+ http.send(request);
+
+ // create a listener for when the request is returned
+ http.onreadystatechange = (e) => {
+ showNames(JSON.parse(http.responseText))
+ }
+}
+
+// Change the page's html to show the generated names
+function showNames(names) {
+
+ // get the name area element
+ var nameArea = document.getElementById("namearea");
+
+ // delete all existing name entries
+ while (nameArea.lastChild) {
+ nameArea.removeChild(nameArea.lastChild);
+ }
+
+ // iterate through all of the given names
+ names.names.forEach((name) => {
+
+ // create the name element
+ var nameElement = document.createElement("p");
+ nameElement.textContent = name;
+ nameElement.classList.add("name");
+
+ // add the name element to the name area
+ nameArea.appendChild(nameElement);
+ });
+}
+
+function updateMap() {
+ // Load the current country of origin
+ var origin = document.getElementById("origin").value;
+
+ console.log(origin)
+
+ // get the canvas context for the worldmap
+ var canvas = document.getElementById("worldmap");
+ var context = canvas.getContext("2d");
+
+ // clear the canvas
+ context.clearRect(0, 0, canvas.width, canvas.height);
+
+ // create the background image
+ var background = new Image();
+ background.src = "/map/background.png"
+
+ // wait for the image to load before trying to draw it
+ background.onload = function() {
+ context.drawImage(background, 0, 0)
+
+ // only draw the country after the background has been drawn
+ var country = new Image();
+ country.src = "/map/" + origin + ".png"
+
+ // wait for the image to load before trying to draw it
+ country.onload = function() {
+ context.drawImage(country, 0, 0)
+ };
+
+ };
+
+}
+
+// force the count to be between 1 and 99
+function forceCount() {
+ var count = parseInt(document.getElementById("number").value);
+ if (count > 99) {
+ document.getElementById("number").value = 99
+ } else if (count < 1) {
+ document.getElementById("number").value = 1
+ }
+}
+
+// toggle the visibility of advanced options
+function toggleAdvanced() {
+ // get the advanced options div
+ var element = document.getElementById("advancedoptions");
+
+ // if display: none, make it visible and vice versa
+ if (element.style.display == "none") {
+ element.style.display = ""
+ } else {
+ element.style.display = "none"
+ }
+
+}
+
+// toggle the checkbox from checked to unchecked and vice versa
+function checkBox(checkbox) {
+ if (checkbox.getAttribute("checked")) {
+ // uncheck the box
+ checkbox.removeAttribute("checked");
+ } else {
+ // set the box to checked
+ checkbox.setAttribute("checked", true);
+ }
+}
diff --git a/src/webserver/dist/style.css b/src/webserver/dist/style.css
new file mode 100644
index 0000000..1ba596d
--- /dev/null
+++ b/src/webserver/dist/style.css
@@ -0,0 +1,138 @@
+#worldmap {
+ width: 50%;
+}
+
+body {
+ font-family: sans-serif;
+ background-color: #191919;
+ color: #f0c674;
+ width:auto;
+}
+
+.main {
+ padding: 0;
+ margin-left: 10%;
+ margin-right: 10%;
+ width: 80%;
+ font-size: 2rem;
+}
+
+#worldmap {
+ width: 50%;
+}
+
+@media (orientation : portrait) {
+ .main {
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ font-size: 1.5rem;
+ }
+
+ #worldmap {
+ width: 100%;
+ }
+}
+
+
+.main {
+ display: inline-block;
+ text-align: center;
+
+}
+
+.box-item {
+ margin-top: 1rem;
+ margin-bottom: 1rem;
+}
+
+
+button,select,input[type=number] {
+ font-size: inherit;
+ background-color: #191919;
+ color: #f0c674;
+ border-radius: 0.5em;
+ text-decoration: none;
+ padding: 0.5rem;
+ border: 0.05rem solid #373b41;
+ box-shadow: 0 0.2em #373b41;
+}
+
+#number {
+ width: 3rem;
+}
+img {
+ width: 2rem;
+}
+
+button:active {
+ background-color: #373b41;
+ box-shadow: 0 0.1em #373b41;
+ transform: translateY(0.1em);
+}
+
+
+.box {
+ margin-top: 10%;
+ padding: 1%;
+ text-align: center;
+ display: inline-block;
+ box-sizing: border-box;
+ margin-left:15%;
+ width: 70%;
+ height: 50%;
+
+ background: transparent;
+ border: 0;
+ outline: 0;
+ border-bottom: 0.25rem solid #0f7d7b;
+ color: #e8922a;
+ font-size: 100%;
+ outline: none !important;
+
+}
+input:focus, textarea {
+ outline: none !important;
+}
+button:focus, textarea {
+ outline: none !important;
+}
+
+
+input[type=checkbox]{
+ position:absolute;
+ opacity: 0;
+ z-index: -9999;
+}
+
+input[type=checkbox] + .indicator {
+ width: 1.5rem;
+ height: 1.5rem;
+ margin-left: 0.5rem;
+ position: absolute;
+
+
+ font-size: inherit;
+ background-color: #191919;
+ color: #191919;
+ border-radius: 0.5em;
+ text-decoration: none;
+ padding: 0.5rem;
+ border: 0.05rem solid #373b41;
+ box-shadow: 0 0.2em #373b41;
+
+ content: "";
+}
+
+input[type=checkbox]:checked + .indicator {
+ background-color: #373b41;
+ box-shadow: 0 0.1em #373b41;
+ transform: translateY(0.1em);
+}
+
+input[type=checkbox]+ .indicator::after {
+ content: "";
+}
+input[type=checkbox]:checked + .indicator::after {
+ content: "X";
+}
diff --git a/src/webserver/dist/subdir/image.png b/src/webserver/dist/subdir/image.png
new file mode 100644
index 0000000..80fb972
--- /dev/null
+++ b/src/webserver/dist/subdir/image.png
Binary files differ
diff --git a/src/webserver/dist/subdir/index.html b/src/webserver/dist/subdir/index.html
new file mode 100644
index 0000000..b7e784a
--- /dev/null
+++ b/src/webserver/dist/subdir/index.html
@@ -0,0 +1 @@
+index of the sub dir
diff --git a/src/webserver/dist/subdir/test.txt b/src/webserver/dist/subdir/test.txt
new file mode 100644
index 0000000..6ee329a
--- /dev/null
+++ b/src/webserver/dist/subdir/test.txt
@@ -0,0 +1 @@
+this is text.txt
diff --git a/src/webserver/pom.xml b/src/webserver/pom.xml
new file mode 100644
index 0000000..c4a716d
--- /dev/null
+++ b/src/webserver/pom.xml
@@ -0,0 +1,47 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>io.github.davidovski.names</groupId>
+ <artifactId>NameGenerator</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.xerial</groupId>
+ <artifactId>sqlite-jdbc</artifactId>
+ <version>3.32.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20210307</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <shadedArtifactAttached>true</shadedArtifactAttached>
+ <transformers>
+ <transformer implementation=
+ "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>io.github.davidovski.names.WebServer</mainClass>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/src/webserver/src/main/java/io/github/davidovski/names/APIRequestHandler.java b/src/webserver/src/main/java/io/github/davidovski/names/APIRequestHandler.java
new file mode 100644
index 0000000..5ef2cfe
--- /dev/null
+++ b/src/webserver/src/main/java/io/github/davidovski/names/APIRequestHandler.java
@@ -0,0 +1,112 @@
+package io.github.davidovski.names;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+@SuppressWarnings("restriction")
+public class APIRequestHandler implements HttpHandler {
+
+ private NameDatabaseManager nameDatabaseManager;
+
+ public APIRequestHandler() {
+ nameDatabaseManager = new NameDatabaseManager(new File("names.db"));
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ // get the requested path
+ String path = exchange.getRequestURI().getPath();
+
+ System.out.println(path);
+
+ if (path.startsWith("/api/name")) {
+
+ // parse the body as a json object
+ JSONTokener jsonParser = new JSONTokener(exchange.getRequestBody());
+ JSONObject json = (JSONObject) jsonParser.nextValue();
+
+ System.out.println(json.toString(2));
+
+ if (json == null) {
+ // Malformed JSON request, 400
+ sendJSON(exchange, (new JSONObject()).put("message", "Malformed JSON body"), 400);
+ return;
+ }
+
+ // generate name(s) and send it
+ generateName(exchange, json);
+ } else {
+ sendJSON(exchange, (new JSONObject()).put("message", "Not Found"), 404);
+ }
+ }
+
+ public void generateName(HttpExchange exchange, JSONObject options) throws JSONException, IOException {
+ String origin = options.optString("origin", "none").toLowerCase();
+
+ int count = options.optInt("count", 1);
+
+ // ensure that the count is between 1-100
+ if (count < 1 || count > 100) {
+ sendJSON(exchange, (new JSONObject()).put("message", "Name count is out of range: Ensure that the request is between 1 and 100 names"), 400);
+ return;
+ }
+
+ String gender = options.optString("gender", "female");
+
+ // ensure that the gender is either male or female
+ if (!gender.equals("male") && !gender.equals("female")) {
+ sendJSON(exchange, (new JSONObject()).put("message", "Requested gender is invalid"), 400);
+ return;
+ }
+
+ // Store the names in an array
+ List<String> names = nameDatabaseManager.getRandomNames(origin, gender, count);
+
+ if (options.optBoolean("surname")) {
+ List<String> surnames = nameDatabaseManager.getRandomNames(origin, "surname", count);
+
+ // Add surnames to the end of each firstname in the names list
+ for (int i = 0; i < count; i++) {
+ String fullname = names.get(i) + " " + surnames.get(i);
+ names.set(i, fullname);
+ }
+ }
+
+ // Create the response json object
+ JSONObject response = new JSONObject();
+ response.put("message", "Generated " + count + " names");
+ response.put("names", new JSONArray(names));
+
+ // send the json back to the client
+ sendJSON(exchange, response, 200);
+ }
+
+ public void sendJSON(HttpExchange exchange, JSONObject json, int responseCode) throws IOException {
+ // convert the json to a string
+ String response = json.toString(2);
+
+ // calculate the response content size
+ int contentSize = response.toString().getBytes().length;
+
+ // set the response headers
+ exchange.getResponseHeaders().add("Content-Type", "text/json");
+ exchange.sendResponseHeaders(responseCode, contentSize);
+
+ // write the response to the output stream
+ OutputStream outputStream = exchange.getResponseBody();
+
+ outputStream.write(response.toString().getBytes());
+ outputStream.close();
+ }
+
+}
diff --git a/src/webserver/src/main/java/io/github/davidovski/names/NameDatabaseManager.java b/src/webserver/src/main/java/io/github/davidovski/names/NameDatabaseManager.java
new file mode 100644
index 0000000..8822d9c
--- /dev/null
+++ b/src/webserver/src/main/java/io/github/davidovski/names/NameDatabaseManager.java
@@ -0,0 +1,75 @@
+package io.github.davidovski.names;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class NameDatabaseManager {
+ private File databaseFile;
+ private Connection connection;
+
+ private static final String TABLE = "names";
+
+ public NameDatabaseManager(File databaseFile) {
+ this.databaseFile = databaseFile;
+
+ connect();
+ }
+
+ /**
+ * Creates a connection to the database. If one could not be created, the connection will remain as null
+ */
+ private void connect() {
+ connection = null;
+ try {
+ connection = DriverManager.getConnection("jdbc:sqlite:" + databaseFile.getPath());
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public List<String> getRandomNames(String origin, String category, int quantitiy) {
+ // create the set to return, even if empty
+ List<String> names = new ArrayList<String>();
+
+ if (connection != null) {
+ // Create an sql statement
+ String sql = "SELECT Name FROM " + TABLE + " WHERE Origin=? AND Category=? ORDER BY RANDOM() LIMIT ?;";
+ PreparedStatement statement;
+ try {
+ statement = connection.prepareStatement(sql);
+
+ // insert relevant values into the statement
+ statement.setString(1, origin);
+ statement.setString(2, category);
+ statement.setInt(3, quantitiy);
+
+ // execute the query and get the result
+ ResultSet result = statement.executeQuery();
+
+ // Add all of the results to the names set
+ while (result.next()) {
+ String name = result.getString("Name");
+ names.add(name);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ }
+ return names;
+ }
+
+ public static void main(String[] args) {
+ NameDatabaseManager dbManager = new NameDatabaseManager(new File("names.db"));
+ List<String> names = dbManager.getRandomNames("spain", "female", 10);
+ for (String name : names) {
+ System.out.println(name);
+ }
+ }
+}
diff --git a/src/webserver/src/main/java/io/github/davidovski/names/StaticRequestHandler.java b/src/webserver/src/main/java/io/github/davidovski/names/StaticRequestHandler.java
new file mode 100644
index 0000000..d10d0b1
--- /dev/null
+++ b/src/webserver/src/main/java/io/github/davidovski/names/StaticRequestHandler.java
@@ -0,0 +1,85 @@
+package io.github.davidovski.names;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+
+@SuppressWarnings("restriction")
+public class StaticRequestHandler implements HttpHandler {
+ private File root;
+
+ public StaticRequestHandler(File root) {
+ this.root = root;
+ }
+
+ @Override
+ public void handle(HttpExchange exchange) throws IOException {
+ // get the requested path
+ String path = exchange.getRequestURI().getPath();
+
+ File requested = new File(root, path);
+
+ // automatically send the index of a directory
+ if (requested.isDirectory()) {
+ requested = new File(requested, "index.html");
+ }
+
+ // ensure that the file is in the intended document root
+ if (!isInRoot(requested, root)) {
+ sendText(exchange, "Access Denied", 403);
+ } else if (requested.exists()) {
+ sendFile(exchange, requested);
+ } else {
+ // send 404 if the file isnt found
+ sendText(exchange, "File Not Found", 404);
+ }
+ }
+
+ private void sendFile(HttpExchange exchange, File file) throws IOException {
+ // read the file as into an array of bytes
+ byte[] bytes = Files.readAllBytes(file.toPath());
+
+ // send the file headers
+ exchange.sendResponseHeaders(200, bytes.length);
+
+ // send the file body
+ OutputStream os = exchange.getResponseBody();
+ os.write(bytes);
+ os.close();
+ }
+
+ private void sendText(HttpExchange exchange, String response, int responseCode) throws IOException {
+ // calculate the response content size
+ int contentSize = response.toString().getBytes().length;
+
+ // set the response headers
+ exchange.getResponseHeaders().add("Content-Type", "text/json");
+ exchange.sendResponseHeaders(responseCode, contentSize);
+
+ // write the response to the output stream
+ OutputStream outputStream = exchange.getResponseBody();
+
+ outputStream.write(response.toString().getBytes());
+ outputStream.close();
+ }
+
+ public static boolean isInRoot(File request, File root) {
+ File parentFile = request;
+
+ // start from the requested file and traverse upwards until reaching the root directory
+ while (parentFile != null) {
+ if (root.equals(parentFile)) {
+ return true;
+ }
+ parentFile = parentFile.getParentFile();
+ }
+
+ // If there isn't a parent file, return false
+ return false;
+ }
+
+}
diff --git a/src/webserver/src/main/java/io/github/davidovski/names/WebServer.java b/src/webserver/src/main/java/io/github/davidovski/names/WebServer.java
new file mode 100644
index 0000000..60b311f
--- /dev/null
+++ b/src/webserver/src/main/java/io/github/davidovski/names/WebServer.java
@@ -0,0 +1,51 @@
+package io.github.davidovski.names;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+import com.sun.net.httpserver.HttpServer;
+
+@SuppressWarnings("restriction")
+public class WebServer {
+ private int port;
+ private HttpServer server;
+
+ public WebServer(int port) throws IOException {
+ this.port = port;
+
+ // create an HTTP server instance
+ InetSocketAddress socketAddress = new InetSocketAddress(port);
+ server = HttpServer.create(socketAddress, 0);
+
+ // create a context for the static request handler
+ server.createContext("/", new StaticRequestHandler(new File("dist")));
+ // create a context for the api request handler
+ server.createContext("/api", new APIRequestHandler());
+
+ }
+
+ public void start() {
+ server.start();
+
+ // tell the user that the webserver has been started, and the port used
+ System.out.println("Webserver started on port " + port);
+ }
+
+
+ public static void main(String[] args) throws IOException {
+
+ // set a default port number
+ int port = 8080;
+
+ // parse the arguments for a port number
+ if (args.length > 0)
+ port = Integer.parseInt(args[0]);
+
+ // Create the webserver instance
+ WebServer webServer = new WebServer(port);
+
+ // start the webserver
+ webServer.start();
+ }
+}