From 290c68795d8100cc97b8b53d80f331e536fc71b1 Mon Sep 17 00:00:00 2001 From: davidovski Date: Wed, 30 Nov 2022 10:06:56 +0000 Subject: Added files to repository --- README.md | 11 + src/neuralnetwork/clean_data.py | 59 + src/neuralnetwork/data/ipa.csv | 174 + src/neuralnetwork/data/names/English.txt | 3668 ++++++++++++++++++++ src/neuralnetwork/generate_alphabets.py | 44 + src/neuralnetwork/rnn.py | 329 ++ src/neuralnetwork/training.py | 373 ++ src/neuralnetwork/util.py | 185 + src/webserver/dist/index.html | 122 + src/webserver/dist/map/afghanistan.png | Bin 0 -> 23211 bytes src/webserver/dist/map/albania.png | Bin 0 -> 6638 bytes src/webserver/dist/map/angolia.png | Bin 0 -> 27027 bytes src/webserver/dist/map/argentina.png | Bin 0 -> 34781 bytes src/webserver/dist/map/austria.png | Bin 0 -> 8881 bytes src/webserver/dist/map/azerbaijan.png | Bin 0 -> 22534 bytes src/webserver/dist/map/background.png | Bin 0 -> 685688 bytes src/webserver/dist/map/bangladesh.png | Bin 0 -> 7277 bytes src/webserver/dist/map/botswana.png | Bin 0 -> 24443 bytes src/webserver/dist/map/brazil.png | Bin 0 -> 42215 bytes src/webserver/dist/map/brunei.png | Bin 0 -> 6900 bytes src/webserver/dist/map/bulgaria.png | Bin 0 -> 22835 bytes src/webserver/dist/map/burundi.png | Bin 0 -> 7502 bytes src/webserver/dist/map/cambodia.png | Bin 0 -> 8653 bytes src/webserver/dist/map/cameroon.png | Bin 0 -> 25309 bytes src/webserver/dist/map/canada.png | Bin 0 -> 116756 bytes src/webserver/dist/map/chile.png | Bin 0 -> 19420 bytes src/webserver/dist/map/colombia.png | Bin 0 -> 26597 bytes src/webserver/dist/map/costa.png | Bin 0 -> 7024 bytes src/webserver/dist/map/croatia.png | Bin 0 -> 8524 bytes src/webserver/dist/map/cyprus.png | Bin 0 -> 8163 bytes src/webserver/dist/map/czech.png | Bin 0 -> 8929 bytes src/webserver/dist/map/denmark.png | Bin 0 -> 7671 bytes src/webserver/dist/map/dibouti.png | Bin 0 -> 7311 bytes src/webserver/dist/map/ecuador.png | Bin 0 -> 22644 bytes src/webserver/dist/map/estonia.png | Bin 0 -> 8392 bytes src/webserver/dist/map/ethopia.png | Bin 0 -> 26251 bytes src/webserver/dist/map/fiji.png | Bin 0 -> 6769 bytes src/webserver/dist/map/finland.png | Bin 0 -> 26057 bytes src/webserver/dist/map/haiti.png | Bin 0 -> 8111 bytes src/webserver/dist/map/honduras.png | Bin 0 -> 8963 bytes src/webserver/dist/map/hungary.png | Bin 0 -> 8481 bytes src/webserver/dist/map/iceland.png | Bin 0 -> 23212 bytes src/webserver/dist/map/india.png | Bin 0 -> 32085 bytes src/webserver/dist/map/indonesia.png | Bin 0 -> 36017 bytes src/webserver/dist/map/iran.png | Bin 0 -> 29620 bytes src/webserver/dist/map/ireland.png | Bin 0 -> 8956 bytes src/webserver/dist/map/israel.png | Bin 0 -> 7630 bytes src/webserver/dist/map/italy.png | Bin 0 -> 25329 bytes src/webserver/dist/map/jamaica.png | Bin 0 -> 7326 bytes src/webserver/dist/map/lithunia.png | Bin 0 -> 9185 bytes src/webserver/dist/map/luxemburj.png | Bin 0 -> 6768 bytes src/webserver/dist/map/macao.png | Bin 0 -> 6767 bytes src/webserver/dist/map/malaysia.png | Bin 0 -> 24856 bytes src/webserver/dist/map/malta.png | Bin 0 -> 6767 bytes src/webserver/dist/map/mauritius.png | Bin 0 -> 6768 bytes src/webserver/dist/map/mexico.png | Bin 0 -> 31649 bytes src/webserver/dist/map/moldova.png | Bin 0 -> 7755 bytes src/webserver/dist/map/namibia.png | Bin 0 -> 24016 bytes src/webserver/dist/map/netherland.png | Bin 0 -> 7973 bytes src/webserver/dist/map/nigeria.png | Bin 0 -> 24703 bytes src/webserver/dist/map/norway.png | Bin 0 -> 25462 bytes src/webserver/dist/map/panama.png | Bin 0 -> 8636 bytes src/webserver/dist/map/peru.png | Bin 0 -> 27826 bytes src/webserver/dist/map/philpine.png | Bin 0 -> 11118 bytes src/webserver/dist/map/poland.png | Bin 0 -> 24402 bytes src/webserver/dist/map/portugal.png | Bin 0 -> 8289 bytes src/webserver/dist/map/puerto_rico.png | Bin 0 -> 8158 bytes src/webserver/dist/map/russia.png | Bin 0 -> 98363 bytes src/webserver/dist/map/serbia.png | Bin 0 -> 22624 bytes src/webserver/dist/map/singapore.png | Bin 0 -> 7405 bytes src/webserver/dist/map/slovenia.png | Bin 0 -> 7381 bytes src/webserver/dist/map/south_africa.png | Bin 0 -> 28681 bytes src/webserver/dist/map/spain.png | Bin 0 -> 23987 bytes src/webserver/dist/map/sweden.png | Bin 0 -> 28746 bytes src/webserver/dist/map/switzerland.png | Bin 0 -> 8243 bytes src/webserver/dist/map/taiwan.png | Bin 0 -> 7412 bytes src/webserver/dist/map/uk.png | Bin 0 -> 25004 bytes src/webserver/dist/map/usa.png | Bin 0 -> 58284 bytes src/webserver/dist/site.js | 129 + src/webserver/dist/style.css | 138 + src/webserver/dist/subdir/image.png | Bin 0 -> 226933 bytes src/webserver/dist/subdir/index.html | 1 + src/webserver/dist/subdir/test.txt | 1 + src/webserver/pom.xml | 47 + .../github/davidovski/names/APIRequestHandler.java | 112 + .../davidovski/names/NameDatabaseManager.java | 75 + .../davidovski/names/StaticRequestHandler.java | 85 + .../java/io/github/davidovski/names/WebServer.java | 51 + 88 files changed, 5604 insertions(+) create mode 100644 README.md create mode 100644 src/neuralnetwork/clean_data.py create mode 100644 src/neuralnetwork/data/ipa.csv create mode 100755 src/neuralnetwork/data/names/English.txt create mode 100644 src/neuralnetwork/generate_alphabets.py create mode 100644 src/neuralnetwork/rnn.py create mode 100644 src/neuralnetwork/training.py create mode 100644 src/neuralnetwork/util.py create mode 100644 src/webserver/dist/index.html create mode 100644 src/webserver/dist/map/afghanistan.png create mode 100644 src/webserver/dist/map/albania.png create mode 100644 src/webserver/dist/map/angolia.png create mode 100644 src/webserver/dist/map/argentina.png create mode 100644 src/webserver/dist/map/austria.png create mode 100644 src/webserver/dist/map/azerbaijan.png create mode 100644 src/webserver/dist/map/background.png create mode 100644 src/webserver/dist/map/bangladesh.png create mode 100644 src/webserver/dist/map/botswana.png create mode 100644 src/webserver/dist/map/brazil.png create mode 100644 src/webserver/dist/map/brunei.png create mode 100644 src/webserver/dist/map/bulgaria.png create mode 100644 src/webserver/dist/map/burundi.png create mode 100644 src/webserver/dist/map/cambodia.png create mode 100644 src/webserver/dist/map/cameroon.png create mode 100644 src/webserver/dist/map/canada.png create mode 100644 src/webserver/dist/map/chile.png create mode 100644 src/webserver/dist/map/colombia.png create mode 100644 src/webserver/dist/map/costa.png create mode 100644 src/webserver/dist/map/croatia.png create mode 100644 src/webserver/dist/map/cyprus.png create mode 100644 src/webserver/dist/map/czech.png create mode 100644 src/webserver/dist/map/denmark.png create mode 100644 src/webserver/dist/map/dibouti.png create mode 100644 src/webserver/dist/map/ecuador.png create mode 100644 src/webserver/dist/map/estonia.png create mode 100644 src/webserver/dist/map/ethopia.png create mode 100644 src/webserver/dist/map/fiji.png create mode 100644 src/webserver/dist/map/finland.png create mode 100644 src/webserver/dist/map/haiti.png create mode 100644 src/webserver/dist/map/honduras.png create mode 100644 src/webserver/dist/map/hungary.png create mode 100644 src/webserver/dist/map/iceland.png create mode 100644 src/webserver/dist/map/india.png create mode 100644 src/webserver/dist/map/indonesia.png create mode 100644 src/webserver/dist/map/iran.png create mode 100644 src/webserver/dist/map/ireland.png create mode 100644 src/webserver/dist/map/israel.png create mode 100644 src/webserver/dist/map/italy.png create mode 100644 src/webserver/dist/map/jamaica.png create mode 100644 src/webserver/dist/map/lithunia.png create mode 100644 src/webserver/dist/map/luxemburj.png create mode 100644 src/webserver/dist/map/macao.png create mode 100644 src/webserver/dist/map/malaysia.png create mode 100644 src/webserver/dist/map/malta.png create mode 100644 src/webserver/dist/map/mauritius.png create mode 100644 src/webserver/dist/map/mexico.png create mode 100644 src/webserver/dist/map/moldova.png create mode 100644 src/webserver/dist/map/namibia.png create mode 100644 src/webserver/dist/map/netherland.png create mode 100644 src/webserver/dist/map/nigeria.png create mode 100644 src/webserver/dist/map/norway.png create mode 100644 src/webserver/dist/map/panama.png create mode 100644 src/webserver/dist/map/peru.png create mode 100644 src/webserver/dist/map/philpine.png create mode 100644 src/webserver/dist/map/poland.png create mode 100644 src/webserver/dist/map/portugal.png create mode 100644 src/webserver/dist/map/puerto_rico.png create mode 100644 src/webserver/dist/map/russia.png create mode 100644 src/webserver/dist/map/serbia.png create mode 100644 src/webserver/dist/map/singapore.png create mode 100644 src/webserver/dist/map/slovenia.png create mode 100644 src/webserver/dist/map/south_africa.png create mode 100644 src/webserver/dist/map/spain.png create mode 100644 src/webserver/dist/map/sweden.png create mode 100644 src/webserver/dist/map/switzerland.png create mode 100644 src/webserver/dist/map/taiwan.png create mode 100644 src/webserver/dist/map/uk.png create mode 100644 src/webserver/dist/map/usa.png create mode 100644 src/webserver/dist/site.js create mode 100644 src/webserver/dist/style.css create mode 100644 src/webserver/dist/subdir/image.png create mode 100644 src/webserver/dist/subdir/index.html create mode 100644 src/webserver/dist/subdir/test.txt create mode 100644 src/webserver/pom.xml create mode 100644 src/webserver/src/main/java/io/github/davidovski/names/APIRequestHandler.java create mode 100644 src/webserver/src/main/java/io/github/davidovski/names/NameDatabaseManager.java create mode 100644 src/webserver/src/main/java/io/github/davidovski/names/StaticRequestHandler.java create mode 100644 src/webserver/src/main/java/io/github/davidovski/names/WebServer.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d70374 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +Hosted on: [name-generator.uk.to](https://name-generator.uk.to) + +# Name Generator + +This is the source code of the recurrent neural network name generator that I created for my NEA project. The idea behind the project was to generate unique looking names from an existing dataset of real names, with various categories for different genders and countries. + +This repository features two parts: +- Python name generator, including the Recurrent Neural Network +- Java webserver which hosts the javascript web app + +Unfortunately I have decided to not include the report that I wrote on this project to avoid any issues with collusion, however generally I have tried my best to document and explain the code itself. 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 @@ + + + + + Name Generator + + + + + + + + + +
+

Name Generator

+ +
+ +
+ + + +
+ + + +
+ + + + +
+ +
+ + +
+ + + + diff --git a/src/webserver/dist/map/afghanistan.png b/src/webserver/dist/map/afghanistan.png new file mode 100644 index 0000000..49abc92 Binary files /dev/null and b/src/webserver/dist/map/afghanistan.png differ diff --git a/src/webserver/dist/map/albania.png b/src/webserver/dist/map/albania.png new file mode 100644 index 0000000..c045c57 Binary files /dev/null and b/src/webserver/dist/map/albania.png differ diff --git a/src/webserver/dist/map/angolia.png b/src/webserver/dist/map/angolia.png new file mode 100644 index 0000000..2e415e5 Binary files /dev/null and b/src/webserver/dist/map/angolia.png differ diff --git a/src/webserver/dist/map/argentina.png b/src/webserver/dist/map/argentina.png new file mode 100644 index 0000000..458376c Binary files /dev/null and b/src/webserver/dist/map/argentina.png differ diff --git a/src/webserver/dist/map/austria.png b/src/webserver/dist/map/austria.png new file mode 100644 index 0000000..f3ed00e Binary files /dev/null and b/src/webserver/dist/map/austria.png differ diff --git a/src/webserver/dist/map/azerbaijan.png b/src/webserver/dist/map/azerbaijan.png new file mode 100644 index 0000000..430b9d6 Binary files /dev/null and b/src/webserver/dist/map/azerbaijan.png differ diff --git a/src/webserver/dist/map/background.png b/src/webserver/dist/map/background.png new file mode 100644 index 0000000..77802f6 Binary files /dev/null and b/src/webserver/dist/map/background.png differ diff --git a/src/webserver/dist/map/bangladesh.png b/src/webserver/dist/map/bangladesh.png new file mode 100644 index 0000000..8fdf65a Binary files /dev/null and b/src/webserver/dist/map/bangladesh.png differ diff --git a/src/webserver/dist/map/botswana.png b/src/webserver/dist/map/botswana.png new file mode 100644 index 0000000..ec58775 Binary files /dev/null and b/src/webserver/dist/map/botswana.png differ diff --git a/src/webserver/dist/map/brazil.png b/src/webserver/dist/map/brazil.png new file mode 100644 index 0000000..8ba32c5 Binary files /dev/null and b/src/webserver/dist/map/brazil.png differ diff --git a/src/webserver/dist/map/brunei.png b/src/webserver/dist/map/brunei.png new file mode 100644 index 0000000..c518380 Binary files /dev/null and b/src/webserver/dist/map/brunei.png differ diff --git a/src/webserver/dist/map/bulgaria.png b/src/webserver/dist/map/bulgaria.png new file mode 100644 index 0000000..c8edece Binary files /dev/null and b/src/webserver/dist/map/bulgaria.png differ diff --git a/src/webserver/dist/map/burundi.png b/src/webserver/dist/map/burundi.png new file mode 100644 index 0000000..3f8d894 Binary files /dev/null and b/src/webserver/dist/map/burundi.png differ diff --git a/src/webserver/dist/map/cambodia.png b/src/webserver/dist/map/cambodia.png new file mode 100644 index 0000000..c92c6f3 Binary files /dev/null and b/src/webserver/dist/map/cambodia.png differ diff --git a/src/webserver/dist/map/cameroon.png b/src/webserver/dist/map/cameroon.png new file mode 100644 index 0000000..b5b57ea Binary files /dev/null and b/src/webserver/dist/map/cameroon.png differ diff --git a/src/webserver/dist/map/canada.png b/src/webserver/dist/map/canada.png new file mode 100644 index 0000000..7358637 Binary files /dev/null and b/src/webserver/dist/map/canada.png differ diff --git a/src/webserver/dist/map/chile.png b/src/webserver/dist/map/chile.png new file mode 100644 index 0000000..e0a3c50 Binary files /dev/null and b/src/webserver/dist/map/chile.png differ diff --git a/src/webserver/dist/map/colombia.png b/src/webserver/dist/map/colombia.png new file mode 100644 index 0000000..3859cc0 Binary files /dev/null and b/src/webserver/dist/map/colombia.png differ diff --git a/src/webserver/dist/map/costa.png b/src/webserver/dist/map/costa.png new file mode 100644 index 0000000..035badd Binary files /dev/null and b/src/webserver/dist/map/costa.png differ diff --git a/src/webserver/dist/map/croatia.png b/src/webserver/dist/map/croatia.png new file mode 100644 index 0000000..1ce5650 Binary files /dev/null and b/src/webserver/dist/map/croatia.png differ diff --git a/src/webserver/dist/map/cyprus.png b/src/webserver/dist/map/cyprus.png new file mode 100644 index 0000000..ea90e2a Binary files /dev/null and b/src/webserver/dist/map/cyprus.png differ diff --git a/src/webserver/dist/map/czech.png b/src/webserver/dist/map/czech.png new file mode 100644 index 0000000..9f89545 Binary files /dev/null and b/src/webserver/dist/map/czech.png differ diff --git a/src/webserver/dist/map/denmark.png b/src/webserver/dist/map/denmark.png new file mode 100644 index 0000000..bef926b Binary files /dev/null and b/src/webserver/dist/map/denmark.png differ diff --git a/src/webserver/dist/map/dibouti.png b/src/webserver/dist/map/dibouti.png new file mode 100644 index 0000000..43015e8 Binary files /dev/null and b/src/webserver/dist/map/dibouti.png differ diff --git a/src/webserver/dist/map/ecuador.png b/src/webserver/dist/map/ecuador.png new file mode 100644 index 0000000..bf2e9d4 Binary files /dev/null and b/src/webserver/dist/map/ecuador.png differ diff --git a/src/webserver/dist/map/estonia.png b/src/webserver/dist/map/estonia.png new file mode 100644 index 0000000..fa6ac33 Binary files /dev/null and b/src/webserver/dist/map/estonia.png differ diff --git a/src/webserver/dist/map/ethopia.png b/src/webserver/dist/map/ethopia.png new file mode 100644 index 0000000..207b3e7 Binary files /dev/null and b/src/webserver/dist/map/ethopia.png differ diff --git a/src/webserver/dist/map/fiji.png b/src/webserver/dist/map/fiji.png new file mode 100644 index 0000000..b574fc9 Binary files /dev/null and b/src/webserver/dist/map/fiji.png differ diff --git a/src/webserver/dist/map/finland.png b/src/webserver/dist/map/finland.png new file mode 100644 index 0000000..1a2754e Binary files /dev/null and b/src/webserver/dist/map/finland.png differ diff --git a/src/webserver/dist/map/haiti.png b/src/webserver/dist/map/haiti.png new file mode 100644 index 0000000..c0773a6 Binary files /dev/null and b/src/webserver/dist/map/haiti.png differ diff --git a/src/webserver/dist/map/honduras.png b/src/webserver/dist/map/honduras.png new file mode 100644 index 0000000..fa7442d Binary files /dev/null and b/src/webserver/dist/map/honduras.png differ diff --git a/src/webserver/dist/map/hungary.png b/src/webserver/dist/map/hungary.png new file mode 100644 index 0000000..97d9e91 Binary files /dev/null and b/src/webserver/dist/map/hungary.png differ diff --git a/src/webserver/dist/map/iceland.png b/src/webserver/dist/map/iceland.png new file mode 100644 index 0000000..d1f0e7d Binary files /dev/null and b/src/webserver/dist/map/iceland.png differ diff --git a/src/webserver/dist/map/india.png b/src/webserver/dist/map/india.png new file mode 100644 index 0000000..e0fc17b Binary files /dev/null and b/src/webserver/dist/map/india.png differ diff --git a/src/webserver/dist/map/indonesia.png b/src/webserver/dist/map/indonesia.png new file mode 100644 index 0000000..c31bf40 Binary files /dev/null and b/src/webserver/dist/map/indonesia.png differ diff --git a/src/webserver/dist/map/iran.png b/src/webserver/dist/map/iran.png new file mode 100644 index 0000000..2ee5b2b Binary files /dev/null and b/src/webserver/dist/map/iran.png differ diff --git a/src/webserver/dist/map/ireland.png b/src/webserver/dist/map/ireland.png new file mode 100644 index 0000000..92fd6dc Binary files /dev/null and b/src/webserver/dist/map/ireland.png differ diff --git a/src/webserver/dist/map/israel.png b/src/webserver/dist/map/israel.png new file mode 100644 index 0000000..3c350f2 Binary files /dev/null and b/src/webserver/dist/map/israel.png differ diff --git a/src/webserver/dist/map/italy.png b/src/webserver/dist/map/italy.png new file mode 100644 index 0000000..fb18140 Binary files /dev/null and b/src/webserver/dist/map/italy.png differ diff --git a/src/webserver/dist/map/jamaica.png b/src/webserver/dist/map/jamaica.png new file mode 100644 index 0000000..0cc2224 Binary files /dev/null and b/src/webserver/dist/map/jamaica.png differ diff --git a/src/webserver/dist/map/lithunia.png b/src/webserver/dist/map/lithunia.png new file mode 100644 index 0000000..633fc4b Binary files /dev/null and b/src/webserver/dist/map/lithunia.png differ diff --git a/src/webserver/dist/map/luxemburj.png b/src/webserver/dist/map/luxemburj.png new file mode 100644 index 0000000..c296bd0 Binary files /dev/null and b/src/webserver/dist/map/luxemburj.png differ diff --git a/src/webserver/dist/map/macao.png b/src/webserver/dist/map/macao.png new file mode 100644 index 0000000..8c3017b Binary files /dev/null and b/src/webserver/dist/map/macao.png differ diff --git a/src/webserver/dist/map/malaysia.png b/src/webserver/dist/map/malaysia.png new file mode 100644 index 0000000..7c14b5a Binary files /dev/null and b/src/webserver/dist/map/malaysia.png differ diff --git a/src/webserver/dist/map/malta.png b/src/webserver/dist/map/malta.png new file mode 100644 index 0000000..bdbfc49 Binary files /dev/null and b/src/webserver/dist/map/malta.png differ diff --git a/src/webserver/dist/map/mauritius.png b/src/webserver/dist/map/mauritius.png new file mode 100644 index 0000000..6e39be8 Binary files /dev/null and b/src/webserver/dist/map/mauritius.png differ diff --git a/src/webserver/dist/map/mexico.png b/src/webserver/dist/map/mexico.png new file mode 100644 index 0000000..ac7d570 Binary files /dev/null and b/src/webserver/dist/map/mexico.png differ diff --git a/src/webserver/dist/map/moldova.png b/src/webserver/dist/map/moldova.png new file mode 100644 index 0000000..aea9bb2 Binary files /dev/null and b/src/webserver/dist/map/moldova.png differ diff --git a/src/webserver/dist/map/namibia.png b/src/webserver/dist/map/namibia.png new file mode 100644 index 0000000..013eb0c Binary files /dev/null and b/src/webserver/dist/map/namibia.png differ diff --git a/src/webserver/dist/map/netherland.png b/src/webserver/dist/map/netherland.png new file mode 100644 index 0000000..ea929f8 Binary files /dev/null and b/src/webserver/dist/map/netherland.png differ diff --git a/src/webserver/dist/map/nigeria.png b/src/webserver/dist/map/nigeria.png new file mode 100644 index 0000000..fbb8c81 Binary files /dev/null and b/src/webserver/dist/map/nigeria.png differ diff --git a/src/webserver/dist/map/norway.png b/src/webserver/dist/map/norway.png new file mode 100644 index 0000000..8246c98 Binary files /dev/null and b/src/webserver/dist/map/norway.png differ diff --git a/src/webserver/dist/map/panama.png b/src/webserver/dist/map/panama.png new file mode 100644 index 0000000..2a080cb Binary files /dev/null and b/src/webserver/dist/map/panama.png differ diff --git a/src/webserver/dist/map/peru.png b/src/webserver/dist/map/peru.png new file mode 100644 index 0000000..c0c759b Binary files /dev/null and b/src/webserver/dist/map/peru.png differ diff --git a/src/webserver/dist/map/philpine.png b/src/webserver/dist/map/philpine.png new file mode 100644 index 0000000..4301c70 Binary files /dev/null and b/src/webserver/dist/map/philpine.png differ diff --git a/src/webserver/dist/map/poland.png b/src/webserver/dist/map/poland.png new file mode 100644 index 0000000..f16d57f Binary files /dev/null and b/src/webserver/dist/map/poland.png differ diff --git a/src/webserver/dist/map/portugal.png b/src/webserver/dist/map/portugal.png new file mode 100644 index 0000000..bdec23d Binary files /dev/null and b/src/webserver/dist/map/portugal.png 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 Binary files /dev/null and b/src/webserver/dist/map/puerto_rico.png differ diff --git a/src/webserver/dist/map/russia.png b/src/webserver/dist/map/russia.png new file mode 100644 index 0000000..e77b48f Binary files /dev/null and b/src/webserver/dist/map/russia.png differ diff --git a/src/webserver/dist/map/serbia.png b/src/webserver/dist/map/serbia.png new file mode 100644 index 0000000..c3debe2 Binary files /dev/null and b/src/webserver/dist/map/serbia.png differ diff --git a/src/webserver/dist/map/singapore.png b/src/webserver/dist/map/singapore.png new file mode 100644 index 0000000..59e3aec Binary files /dev/null and b/src/webserver/dist/map/singapore.png differ diff --git a/src/webserver/dist/map/slovenia.png b/src/webserver/dist/map/slovenia.png new file mode 100644 index 0000000..1dd5ebf Binary files /dev/null and b/src/webserver/dist/map/slovenia.png 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 Binary files /dev/null and b/src/webserver/dist/map/south_africa.png differ diff --git a/src/webserver/dist/map/spain.png b/src/webserver/dist/map/spain.png new file mode 100644 index 0000000..b6947e3 Binary files /dev/null and b/src/webserver/dist/map/spain.png differ diff --git a/src/webserver/dist/map/sweden.png b/src/webserver/dist/map/sweden.png new file mode 100644 index 0000000..6b7ba10 Binary files /dev/null and b/src/webserver/dist/map/sweden.png differ diff --git a/src/webserver/dist/map/switzerland.png b/src/webserver/dist/map/switzerland.png new file mode 100644 index 0000000..6a8180a Binary files /dev/null and b/src/webserver/dist/map/switzerland.png differ diff --git a/src/webserver/dist/map/taiwan.png b/src/webserver/dist/map/taiwan.png new file mode 100644 index 0000000..ca08390 Binary files /dev/null and b/src/webserver/dist/map/taiwan.png differ diff --git a/src/webserver/dist/map/uk.png b/src/webserver/dist/map/uk.png new file mode 100644 index 0000000..51f6e4d Binary files /dev/null and b/src/webserver/dist/map/uk.png differ diff --git a/src/webserver/dist/map/usa.png b/src/webserver/dist/map/usa.png new file mode 100644 index 0000000..06cabde Binary files /dev/null and b/src/webserver/dist/map/usa.png 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 Binary files /dev/null and b/src/webserver/dist/subdir/image.png 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 @@ + + 4.0.0 + io.github.davidovski.names + NameGenerator + 0.0.1-SNAPSHOT + jar + + + org.xerial + sqlite-jdbc + 3.32.3 + + + org.json + json + 20210307 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + shade + + + true + + + io.github.davidovski.names.WebServer + + + + + + + + + + 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 names = nameDatabaseManager.getRandomNames(origin, gender, count); + + if (options.optBoolean("surname")) { + List 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 getRandomNames(String origin, String category, int quantitiy) { + // create the set to return, even if empty + List names = new ArrayList(); + + 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 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(); + } +} -- cgit v1.2.1