├── DWC.Blazor ├── wwwroot │ ├── favicon.ico │ ├── data │ │ └── devs-pics │ │ │ ├── B_B.jpeg │ │ │ ├── D_G.jpg │ │ │ ├── dummy.png │ │ │ ├── jnovas.jpg │ │ │ ├── c-vivieca.jpeg │ │ │ ├── capellan.jpg │ │ │ ├── cdelacruz.jpeg │ │ │ ├── edwardenis.jpg │ │ │ ├── evaldez89.jpg │ │ │ ├── gavilanch.jpg │ │ │ ├── jefry-pozo.jpg │ │ │ ├── jmaldonado.jpg │ │ │ ├── ming-tsai.jpg │ │ │ ├── angel-garcia.jpg │ │ │ ├── angel-perez.jpg │ │ │ ├── angel-reyes.jpg │ │ │ ├── angel-torres.jpg │ │ │ ├── daniel-feliz.jpg │ │ │ ├── danny-feliz.jpeg │ │ │ ├── dany-santos.jpg │ │ │ ├── eddy-cordero.jpg │ │ │ ├── freilynstr.jpeg │ │ │ ├── ivan-verges.jpg │ │ │ ├── jose-hidalgo.jpg │ │ │ ├── jose-segura.jpg │ │ │ ├── junior-felix.jpg │ │ │ ├── luis-burdier.jpg │ │ │ ├── luis-pujols.png │ │ │ ├── nelson-veras.jpg │ │ │ ├── omar-gaston.jpg │ │ │ ├── raul-montero.jpg │ │ │ ├── steven-checo.jpg │ │ │ ├── wildin-mota.jpeg │ │ │ ├── Raffy_Rodriguez.png │ │ │ ├── albert-hidalgo.jpg │ │ │ ├── alexandro-cueto.jpg │ │ │ ├── carlos-gonzalez.jpg │ │ │ ├── carlos-herasme.jpg │ │ │ ├── claudio-sanchez.jpg │ │ │ ├── dionny-prensa.jpeg │ │ │ ├── enrique-ortiz.jpg │ │ │ ├── enrique-uvinas.jpg │ │ │ ├── gregory-cabral.jpg │ │ │ ├── jadhiel-velez.png │ │ │ ├── jean-calderon.jpg │ │ │ ├── jefri-martinez.jpg │ │ │ ├── jgilbertcastro.jpg │ │ │ ├── leandro-jimenez.PNG │ │ │ ├── leonel-santiago.jpg │ │ │ ├── lewandy-dilone.jpg │ │ │ ├── michael-montero.jpg │ │ │ ├── miguel-hiciano.jpg │ │ │ ├── nelson-minaya.jpg │ │ │ ├── rancell-tapia.jpg │ │ │ ├── raymond-coplin.jpg │ │ │ ├── robert-lluberes.jpg │ │ │ ├── ronel-pantaleon.jpg │ │ │ ├── vyzaldy-sanchez.jpg │ │ │ ├── yhorby-matias.jpeg │ │ │ ├── cristopher-ortega.jpg │ │ │ ├── eleazar-estrella.jpeg │ │ │ ├── genesis-alvarez.jpeg │ │ │ ├── manuel-hernandez.jpg │ │ │ ├── robert-marcelino.jpg │ │ │ ├── francis-goris-payano.jpg │ │ │ ├── francisco-hernandez.jpg │ │ │ └── frangel-rodriguez1-min.jpg │ ├── font-awesome │ │ ├── webfonts │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-solid-900.woff2 │ │ │ └── fa-regular-400.woff2 │ │ ├── css │ │ │ ├── brands.min.css │ │ │ ├── solid.min.css │ │ │ ├── regular.min.css │ │ │ ├── brands.css │ │ │ ├── solid.css │ │ │ ├── regular.css │ │ │ ├── svg-with-js.min.css │ │ │ └── svg-with-js.css │ │ └── js │ │ │ ├── conflict-detection.min.js │ │ │ ├── v4-shims.min.js │ │ │ └── v4-shims.js │ ├── index.html │ ├── twitter-bootstrap │ │ └── css │ │ │ ├── bootstrap-reboot.min.css │ │ │ └── bootstrap-reboot.css │ ├── css │ │ └── site.css │ └── jquery │ │ └── core.js ├── App.razor ├── libman.json ├── _Imports.razor ├── Program.cs ├── DWC.Blazor.csproj ├── Extensions │ └── LinqExtensions.cs ├── Services │ └── CsvExportService.cs ├── Shared │ ├── CardComponent.razor │ └── MainLayout.razor ├── Utils │ ├── UrlValidator.cs │ └── SkillNormalizer.cs └── Pages │ └── Index.razor ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── pull_request_template.md └── workflows │ └── codeql-analysis.yml ├── SECURITY.md ├── DWC.Blazor.Tests ├── DWC.Blazor.Tests.csproj ├── ShuffleAlgorithmTests.cs ├── DevelopersJsonFileTests.cs ├── CardComponentTests.cs ├── SkillNormalizerTests.cs ├── CsvExportServiceTests.cs └── UrlValidatorTests.cs ├── Roadmap.md ├── LICENSE ├── CONTRIBUTING.md ├── azure-pipelines.yml ├── DWC.sln ├── README.md ├── CODE_OF_CONDUCT.md └── .gitignore /DWC.Blazor/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/favicon.ico -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/B_B.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/B_B.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/D_G.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/D_G.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/dummy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/dummy.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "nuget" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jnovas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jnovas.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/c-vivieca.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/c-vivieca.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/capellan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/capellan.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/cdelacruz.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/cdelacruz.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/edwardenis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/edwardenis.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/evaldez89.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/evaldez89.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/gavilanch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/gavilanch.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jefry-pozo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jefry-pozo.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jmaldonado.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jmaldonado.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/ming-tsai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/ming-tsai.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/angel-garcia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/angel-garcia.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/angel-perez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/angel-perez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/angel-reyes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/angel-reyes.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/angel-torres.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/angel-torres.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/daniel-feliz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/daniel-feliz.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/danny-feliz.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/danny-feliz.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/dany-santos.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/dany-santos.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/eddy-cordero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/eddy-cordero.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/freilynstr.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/freilynstr.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/ivan-verges.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/ivan-verges.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jose-hidalgo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jose-hidalgo.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jose-segura.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jose-segura.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/junior-felix.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/junior-felix.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/luis-burdier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/luis-burdier.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/luis-pujols.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/luis-pujols.png -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/nelson-veras.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/nelson-veras.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/omar-gaston.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/omar-gaston.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/raul-montero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/raul-montero.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/steven-checo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/steven-checo.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/wildin-mota.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/wildin-mota.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/Raffy_Rodriguez.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/Raffy_Rodriguez.png -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/albert-hidalgo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/albert-hidalgo.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/alexandro-cueto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/alexandro-cueto.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/carlos-gonzalez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/carlos-gonzalez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/carlos-herasme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/carlos-herasme.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/claudio-sanchez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/claudio-sanchez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/dionny-prensa.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/dionny-prensa.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/enrique-ortiz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/enrique-ortiz.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/enrique-uvinas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/enrique-uvinas.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/gregory-cabral.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/gregory-cabral.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jadhiel-velez.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jadhiel-velez.png -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jean-calderon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jean-calderon.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jefri-martinez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jefri-martinez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/jgilbertcastro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/jgilbertcastro.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/leandro-jimenez.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/leandro-jimenez.PNG -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/leonel-santiago.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/leonel-santiago.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/lewandy-dilone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/lewandy-dilone.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/michael-montero.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/michael-montero.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/miguel-hiciano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/miguel-hiciano.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/nelson-minaya.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/nelson-minaya.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/rancell-tapia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/rancell-tapia.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/raymond-coplin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/raymond-coplin.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/robert-lluberes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/robert-lluberes.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/ronel-pantaleon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/ronel-pantaleon.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/vyzaldy-sanchez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/vyzaldy-sanchez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/yhorby-matias.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/yhorby-matias.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/cristopher-ortega.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/cristopher-ortega.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/eleazar-estrella.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/eleazar-estrella.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/genesis-alvarez.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/genesis-alvarez.jpeg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/manuel-hernandez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/manuel-hernandez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/robert-marcelino.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/robert-marcelino.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/francis-goris-payano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/francis-goris-payano.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/francisco-hernandez.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/francisco-hernandez.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/data/devs-pics/frangel-rodriguez1-min.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/data/devs-pics/frangel-rodriguez1-min.jpg -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/HEAD/DWC.Blazor/wwwroot/font-awesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### General 2 | Write only what you have added, not what your code does. 3 | 4 | ### Type 5 | 6 | > ℹ️ What types of changes does your code introduce? 7 | 8 | > 👉 _Put an `x` in the boxes that apply_ 9 | 10 | - [ ] Fix 11 | - [ ] Feature 12 | 13 | ### Describe the changes here (summarized) 14 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 5.1.x | :white_check_mark: | 8 | | 5.0.x | :x: | 9 | | 4.0.x | :white_check_mark: | 10 | | < 4.0 | :x: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | https://github.com/AngelGarcia13/DominicanWhoCodes/issues 15 | -------------------------------------------------------------------------------- /DWC.Blazor/App.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Sorry, there's nothing at this address.

8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /DWC.Blazor/libman.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "defaultProvider": "cdnjs", 4 | "libraries": [ 5 | { 6 | "library": "twitter-bootstrap@4.3.1", 7 | "destination": "wwwroot/twitter-bootstrap/" 8 | }, 9 | { 10 | "library": "font-awesome@5.10.2", 11 | "destination": "wwwroot/font-awesome/" 12 | }, 13 | { 14 | "library": "jquery@3.4.1", 15 | "destination": "wwwroot/jquery/" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /DWC.Blazor/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using DWC.Blazor 10 | @using DWC.Blazor.Shared 11 | @using DWC.Blazor.Extensions 12 | @using DWC.Blazor.Utils 13 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/brands.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"} -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/solid.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/regular.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400} -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/brands.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Brands'; 7 | font-style: normal; 8 | font-weight: normal; 9 | font-display: auto; 10 | src: url("../webfonts/fa-brands-400.eot"); 11 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); } 12 | 13 | .fab { 14 | font-family: 'Font Awesome 5 Brands'; } 15 | -------------------------------------------------------------------------------- /DWC.Blazor/Program.cs: -------------------------------------------------------------------------------- 1 | using DWC.Blazor.Services; 2 | using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using System; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | namespace DWC.Blazor 9 | { 10 | public class Program 11 | { 12 | public static async Task Main(string[] args) 13 | { 14 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 15 | 16 | builder.RootComponents.Add("#app"); 17 | builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); 18 | builder.Services.AddScoped(); 19 | 20 | await builder.Build().RunAsync(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 900; 9 | font-display: auto; 10 | src: url("../webfonts/fa-solid-900.eot"); 11 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); } 12 | 13 | .fa, 14 | .fas { 15 | font-family: 'Font Awesome 5 Free'; 16 | font-weight: 900; } 17 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | @font-face { 6 | font-family: 'Font Awesome 5 Free'; 7 | font-style: normal; 8 | font-weight: 400; 9 | font-display: auto; 10 | src: url("../webfonts/fa-regular-400.eot"); 11 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); } 12 | 13 | .far { 14 | font-family: 'Font Awesome 5 Free'; 15 | font-weight: 400; } 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /DWC.Blazor/DWC.Blazor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | Exe 6 | 8.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /DWC.Blazor.Tests/DWC.Blazor.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Roadmap.md: -------------------------------------------------------------------------------- 1 | # DominicanWho.Codes Roadmap 2 | 3 | We decided to make a list of the things that will be added to the project, this way the contributors will have a better understanding about what's going on with DominicanWho.Codes (**DWC**). 4 | 5 | Let's start with the big picture, DWC is basically a devs directory where you could find out your next partner, employee or friend from the Dominican Republic, so we started with a simple app made with Blazor where we have the data in a JSON file. 6 | 7 | In next releases there will be features like: Login/Register, Profile/Skills Management and Recommendations on other users profile. 8 | 9 | This project is basically for me and my co-worker Manuel Hernández @ManuHernandez (and everybody who want to collaborate) to learn/use some of the main JS front-end frameworks (Angular, Vue and React), play with some WebAssembly technologies like Blazor and also implement a Microservices Architecture (using various technologies) for the back-end. 10 | 11 | # Development Environment Architecture 12 | ![](https://drive.google.com/uc?export=download&id=1Gm8zGjZjFwuu38FLgnLe-XKUQGrdwrtn) 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Angel Garcia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DWC.Blazor.Tests/ShuffleAlgorithmTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using DWC.Blazor.Extensions; 5 | using Xunit; 6 | 7 | namespace DWC.Blazor.Tests 8 | { 9 | public class ShuffleAlgorithmTests 10 | { 11 | [Fact] 12 | public void Shuffle_NullSource_Should_ThrowsException() 13 | { 14 | // Arrange 15 | List source = null; 16 | 17 | // Act 18 | Action action = () => source.Shuffle().ToList(); 19 | 20 | // Assert 21 | Assert.Throws(action); 22 | } 23 | 24 | [Fact] 25 | public void Shuffle_NullRandom_Should_ThrowsException() 26 | { 27 | // Arrange 28 | var source = new List { 1, 2, 3 }; 29 | Random rand = null; 30 | 31 | // Act 32 | Action action = () => source.Shuffle(rand).ToList(); 33 | 34 | // Assert 35 | Assert.Throws(action); 36 | } 37 | 38 | [Fact] 39 | public void Shuffle_SourceOk_Should_ShuffleList() 40 | { 41 | // Arrange 42 | var source = Enumerable.Range(0, 50); 43 | 44 | // Act 45 | var result = source.Shuffle().ToList(); 46 | 47 | // Assert 48 | Assert.NotEqual(source, result); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to DominicanWhoCodes 2 | 3 | #### **Did you find a bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/AngelGarcia13/DominicanWhoCodes/issues). 6 | 7 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/AngelGarcia13/DominicanWhoCodes/issues/new/choose). Be sure to include a **title and clear description**, and as much relevant information as possible. 8 | 9 | #### **Did you write a patch that fixes a bug?** 10 | 11 | * Open a new GitHub pull request with the patch. 12 | 13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 14 | 15 | #### **Did you fix whitespace, format code, or make a purely cosmetic patch?** 16 | 17 | Changes that are cosmetic and do not add anything substantial to the stability, functionality, or testability of DominicanWhoCodes will generally be accepted. 18 | 19 | #### **Do you have questions about the source code?** 20 | 21 | * Ask any question about DominicanWhoCodes in the [Slack workspace](https://join.slack.com/t/dominicanwhocodes/shared_invite/enQtNzU0MjQ2OTY1MDk1LTcyMTUwODJkNTM2ZTQwYTQ0OWM4ODc4ZTBiOWU1N2Q0ZGY5NmJjZjExZjBjNTE0NGQ2ZjVjZTM2MDBjNmMzNDc) 22 | 23 | DominicanWhoCodes is a volunteer effort. We encourage you to pitch in and [join the team](https://github.com/AngelGarcia13/DominicanWhoCodes/graphs/contributors)! 24 | 25 | Thanks! :heart: :heart: 26 | 27 | Angel Garcia 28 | 29 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | - master 3 | 4 | pool: 5 | vmImage: 'windows-2022' 6 | 7 | variables: 8 | buildConfiguration: 'Release' 9 | dotnetVersion: '8.0.x' 10 | 11 | steps: 12 | - task: UseDotNet@2 13 | displayName: 'Installing .NET Core SDK...' 14 | inputs: 15 | version: $(dotnetVersion) 16 | 17 | - task: DotNetCoreCLI@2 18 | displayName: 'Restore NuGet packages...' 19 | inputs: 20 | command: 'restore' 21 | projects: '**/*.sln' 22 | 23 | - script: | 24 | dotnet workload install wasm-tools 25 | displayName: 'Install WebAssembly workload' 26 | 27 | - task: DotNetCoreCLI@2 28 | displayName: 'Build $(buildConfiguration)' 29 | inputs: 30 | command: 'build' 31 | projects: '**/*.sln' 32 | arguments: '--configuration $(buildConfiguration) --no-restore --verbosity normal' 33 | 34 | - task: DotNetCoreCLI@2 35 | displayName: 'Run tests $(buildConfiguration)' 36 | inputs: 37 | command: 'test' 38 | projects: '**/*Tests.csproj' 39 | arguments: '--configuration $(buildConfiguration) --no-build --logger trx' 40 | 41 | - task: DotNetCoreCLI@2 42 | displayName: 'Publishing App...' 43 | inputs: 44 | command: publish 45 | publishWebProjects: true 46 | arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)' 47 | zipAfterPublish: false 48 | 49 | - task: PublishBuildArtifacts@1 50 | displayName: 'Publishing Build Artifacts' 51 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master')) 52 | inputs: 53 | pathToPublish: '$(Build.ArtifactStagingDirectory)' 54 | artifactName: 'drop' 55 | -------------------------------------------------------------------------------- /DWC.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29519.87 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DWC.Blazor", "DWC.Blazor\DWC.Blazor.csproj", "{EBBD88FA-68FD-444B-9142-E4998C901587}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DWC.Blazor.Tests", "DWC.Blazor.Tests\DWC.Blazor.Tests.csproj", "{23688168-8922-4060-BC0C-4721C9DF4646}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {EBBD88FA-68FD-444B-9142-E4998C901587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {EBBD88FA-68FD-444B-9142-E4998C901587}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {EBBD88FA-68FD-444B-9142-E4998C901587}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {EBBD88FA-68FD-444B-9142-E4998C901587}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {23688168-8922-4060-BC0C-4721C9DF4646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {23688168-8922-4060-BC0C-4721C9DF4646}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {23688168-8922-4060-BC0C-4721C9DF4646}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {23688168-8922-4060-BC0C-4721C9DF4646}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {80BB95A4-F02D-4261-9E0B-F32909A747F2} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /DWC.Blazor/Extensions/LinqExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DWC.Blazor.Extensions 6 | { 7 | public static class LinqExtensions 8 | { 9 | /// Returns a shuffled sequence from the original sequence. 10 | /// The type of the elements of 11 | /// The sequence to shuffle. 12 | /// A new shuffled sequence of 13 | public static IEnumerable Shuffle(this IEnumerable source) 14 | { 15 | return Shuffle(source, new Random()); 16 | } 17 | 18 | /// Returns a shuffled sequence from the original sequence. 19 | /// The type of the elements of 20 | /// The sequence to shuffle. 21 | /// A random generator used as part of the selection algorithm. 22 | /// A new shuffled sequence of 23 | public static IEnumerable Shuffle(this IEnumerable source, Random rand) 24 | { 25 | if (source == null) throw new ArgumentNullException(nameof(source)); 26 | if (rand == null) throw new ArgumentNullException(nameof(rand)); 27 | 28 | T[] array = source.ToArray(); 29 | int length = array.Length; 30 | 31 | for (int i = length - 1; i >= 1; i--) 32 | { 33 | int j = rand.Next(i + 1); 34 | 35 | T buffer = array[i]; 36 | array[i] = array[j]; 37 | array[j] = buffer; 38 | } 39 | 40 | return array; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | DominicanWho.Codes 14 | 15 | 16 |
17 |
18 |
19 | DominicanWho.Codes 20 |
21 |
22 | 23 | 24 | 25 | 26 | 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DominicanWhoCodes 2 | [![Build Status](https://dev.azure.com/angelrenegarcia13/DominicanWhoCodes/_apis/build/status/AngelGarcia13.DominicanWhoCodes?branchName=master)](https://dev.azure.com/angelrenegarcia13/DominicanWhoCodes/_build/latest?definitionId=4&branchName=master) 3 | 4 | Open source project inspired by [Indians 5 | Who Design](http://indianswhodesign.in) was made to expose all the developers from the Dominican Republic with their skills and contacts. 6 | 7 | The idea is to have this directory where you could find the Dominican dev's info, this project is basically for [me](https://github.com/AngelGarcia13) and [ManuHernandez](https://github.com/ManuHernandez) (and everybody who wants to collaborate) to learn/use some of the main JS front-end frameworks (Angular, [Vue](https://dominicanwhocodes.netlify.com) and [React](https://festive-pike-7fadeb.netlify.app/)), play with some WebAssembly technologies like Blazor and also implement a Microservices Architecture. 8 | 9 | See the [Roadmap](Roadmap.md) for more technical details. 10 | 11 | #### Join our Slack. 12 | 13 | [![Slack](https://img.shields.io/badge/slack-%234A154B.svg?&style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/dominicanwhocodes/shared_invite/enQtNzU0MjQ2OTY1MDk1LTcyMTUwODJkNTM2ZTQwYTQ0OWM4ODc4ZTBiOWU1N2Q0ZGY5NmJjZjExZjBjNTE0NGQ2ZjVjZTM2MDBjNmMzNDc) 14 | 15 | ## How to contribute 16 | 17 | > :thought_balloon: If you are new in Open Source world feel free to check our [How to contribute guidelines](https://github.com/AngelGarcia13/DominicanWhoCodes/blob/master/CONTRIBUTING.md) 18 | 19 | ### Blazor Client App. 20 | 21 | 🚀 Amazon S3 Bucket: http://www.dominicanwho.codes.s3-website-us-east-1.amazonaws.com/ 22 | 23 | 🚀 Azure WebApp (Free Tier, could be stopped anytime): http://dominicanwhocodes.azurewebsites.net/ 24 | 25 | ### Vue.js Client App. 26 | 27 | 🚀 Netlify: https://dominicanwhocodes.netlify.com 28 | 29 | 💻 Repo: https://github.com/VueDominicana/DominicanWhoCodes 30 | 31 | ### React Client App. 32 | 33 | 🚀 Netlify: https://festive-pike-7fadeb.netlify.app/ 34 | 35 | 💻 Repo: https://github.com/React-Dominicana/dominicans-who-code-react 36 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '33 21 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp', 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v2 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | -------------------------------------------------------------------------------- /DWC.Blazor/Services/CsvExportService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Text; 6 | using CsvHelper; 7 | using CsvHelper.Configuration; 8 | using static DWC.Blazor.Pages.Index; 9 | 10 | namespace DWC.Blazor.Services 11 | { 12 | public class CsvExportService 13 | { 14 | public byte[] ExportDevelopersToCsv(List developers) 15 | { 16 | if (developers == null || developers.Count == 0) 17 | { 18 | return Array.Empty(); 19 | } 20 | 21 | using var memoryStream = new MemoryStream(); 22 | using var streamWriter = new StreamWriter(memoryStream, new UTF8Encoding(true)); // true = with BOM 23 | using var csvWriter = new CsvWriter(streamWriter, new CsvConfiguration(CultureInfo.InvariantCulture) 24 | { 25 | HasHeaderRecord = true, 26 | }); 27 | 28 | // Write CSV headers 29 | csvWriter.WriteField("Name"); 30 | csvWriter.WriteField("Skills"); 31 | csvWriter.WriteField("Summary"); 32 | csvWriter.WriteField("GitHub"); 33 | csvWriter.WriteField("LinkedIn"); 34 | csvWriter.WriteField("Twitter"); 35 | csvWriter.WriteField("Website"); 36 | csvWriter.NextRecord(); 37 | 38 | // Write developer data 39 | foreach (var developer in developers) 40 | { 41 | csvWriter.WriteField(developer.Name ?? string.Empty); 42 | csvWriter.WriteField(FormatSkills(developer.Skills)); 43 | csvWriter.WriteField(developer.Summary ?? string.Empty); 44 | csvWriter.WriteField(developer.Github ?? string.Empty); 45 | csvWriter.WriteField(developer.LinkedIn ?? string.Empty); 46 | csvWriter.WriteField(developer.Twitter ?? string.Empty); 47 | csvWriter.WriteField(developer.Webpage ?? string.Empty); 48 | csvWriter.NextRecord(); 49 | } 50 | 51 | streamWriter.Flush(); 52 | return memoryStream.ToArray(); 53 | } 54 | 55 | private static string FormatSkills(string skills) 56 | { 57 | if (string.IsNullOrWhiteSpace(skills)) 58 | { 59 | return string.Empty; 60 | } 61 | 62 | // Replace common separators with commas for CSV 63 | return skills 64 | .Replace(" and ", ", ") 65 | .Replace(" & ", ", ") 66 | .Trim(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /DWC.Blazor.Tests/DevelopersJsonFileTests.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.IO; 4 | using Xunit; 5 | using static DWC.Blazor.Pages.Index; 6 | 7 | namespace DWC.Blazor.Tests 8 | { 9 | public class DevelopersJsonFileTests 10 | { 11 | [Fact] 12 | public void JsonFile_Should_DeserializeOk() 13 | { 14 | // Arrange 15 | var projectRoot = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; 16 | var jsonPath = Path.Combine(projectRoot, "DWC.Blazor", "wwwroot", "data", "developers.json"); 17 | var jsonString = File.ReadAllText(jsonPath); 18 | 19 | // Act 20 | var developers = JsonConvert.DeserializeObject(jsonString); 21 | 22 | // Assert 23 | Assert.NotNull(developers); 24 | Assert.NotEmpty(developers); 25 | } 26 | 27 | [Fact] 28 | public void JsonFile_SocialNetworkUrls_Should_HaveValidUrls() 29 | { 30 | // Arrange 31 | var projectRoot = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName; 32 | var jsonPath = Path.Combine(projectRoot, "DWC.Blazor", "wwwroot", "data", "developers.json"); 33 | var jsonString = File.ReadAllText(jsonPath); 34 | 35 | // Act 36 | var developers = JsonConvert.DeserializeObject(jsonString); 37 | 38 | // Assert 39 | foreach (var developer in developers) 40 | { 41 | Assert.True(IsValidUrl(developer.Github), $"{developer.Name} has an invalid Github url"); 42 | Assert.True(IsValidUrl(developer.LinkedIn), $"{developer.Name} has an invalid LinkedIn url"); 43 | Assert.True(IsValidUrl(developer.StackOverflow), $"{developer.Name} has an invalid StackOverflow url"); 44 | Assert.True(IsValidUrl(developer.Twitter), $"{developer.Name} has an invalid Twitter url"); 45 | Assert.True(IsValidUrl(developer.Webpage), $"{developer.Name} has an invalid Webpage url"); 46 | Assert.True(IsValidUrl(developer.YouTube), $"{developer.Name} has an invalid YouTube url"); 47 | Assert.True(IsValidUrl(developer.Telegram), $"{developer.Name} has an invalid Telegram url"); 48 | Assert.True(IsValidUrl(developer.Medium), $"{developer.Name} has an invalid Medium url"); 49 | } 50 | } 51 | 52 | private bool IsValidUrl(string url) 53 | { 54 | if (string.IsNullOrEmpty(url)) 55 | return true; 56 | 57 | return Uri.TryCreate(url, UriKind.Absolute, out _); 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /DWC.Blazor/Shared/CardComponent.razor: -------------------------------------------------------------------------------- 1 |
2 |
Card image cap
3 |
4 |
5 |
6 | @Initials 7 |
8 |
@Name
9 | 10 |
11 |
12 |
13 | @foreach (var skill in @SkillsList) 14 | { 15 | @skill 16 | } 17 |
18 |
19 |
20 |

21 | @Summary 22 |

23 |
24 | 34 |
35 |
36 | 37 | @code { 38 | [Parameter] 39 | public string Name { get; set; } 40 | [Parameter] 41 | public string Initials { get; set; } 42 | [Parameter] 43 | public string Image { get; set; } 44 | [Parameter] 45 | public string Summary { get; set; } 46 | [Parameter] 47 | public string Skills { get; set; } 48 | public string[] SkillsList => Skills.Split(','); 49 | [Parameter] 50 | public string Webpage { get; set; } 51 | [Parameter] 52 | public string LinkedIn { get; set; } 53 | [Parameter] 54 | public string Twitter { get; set; } 55 | [Parameter] 56 | public string Github { get; set; } 57 | [Parameter] 58 | public string Telegram { get; set; } 59 | [Parameter] 60 | public string StackOverflow { get; set; } 61 | [Parameter] 62 | public string Medium { get; set; } 63 | [Parameter] 64 | public string YouTube { get; set; } 65 | } -------------------------------------------------------------------------------- /DWC.Blazor.Tests/CardComponentTests.cs: -------------------------------------------------------------------------------- 1 | using Bunit; 2 | using Bunit.Rendering; 3 | using DWC.Blazor.Shared; 4 | using Xunit; 5 | 6 | namespace DWC.Blazor.Tests 7 | { 8 | public class CardComponentTests 9 | { 10 | [Fact] 11 | public void SocialNetworks_NoLinkedin_Should_Not_DisplayLinkedinLink() 12 | { 13 | // Arrange 14 | using var context = new TestContext(); 15 | 16 | var parameters = new ComponentParameter[] 17 | { 18 | ("Name", "Test Name"), 19 | ("Initials", "TN"), 20 | ("Image", "image.jpg"), 21 | ("Summary", "Test Summary"), 22 | ("Webpage", "http://mypage.com"), 23 | ("Twitter", "http://twitter.com"), 24 | ("Skills","C#, ASP.NET Core, T-SQL, TypeScript, JavaScrpit"), 25 | ("Telegram", "http://telegram.com"), 26 | ("StackOverflow", "http://stackoverflow.com"), 27 | ("Medium", "http://medium.com"), 28 | ("Github", "http://github.com/nminaya"), 29 | ("YouTube", "http://youtube.com") 30 | }; 31 | 32 | // Act 33 | var component = context.RenderComponent(parameters); 34 | 35 | // Assert 36 | Assert.Throws(() => component.Find("div .social-networks .fa-linkedin")); 37 | } 38 | 39 | [Fact] 40 | public void SocialNetworks_AllSocialNetworkFilled_Should_DisplaysAllSocilNetworks() 41 | { 42 | // Arrange 43 | using var context = new TestContext(); 44 | 45 | var parameters = new ComponentParameter[] 46 | { 47 | ("Name", "Test Name"), 48 | ("Initials", "TN"), 49 | ("Image", "image.jpg"), 50 | ("Summary", "Test Summary"), 51 | ("Webpage", "http://mypage.com"), 52 | ("Skills","C#, ASP.NET Core, T-SQL, TypeScript, JavaScrpit"), 53 | ("Twitter", "http://twitter.com"), 54 | ("Telegram", "http://telegram.com"), 55 | ("StackOverflow", "http://stackoverflow.com"), 56 | ("Medium", "http://medium.com"), 57 | ("Github", "http://github.com"), 58 | ("YouTube", "http://youtube.com"), 59 | ("LinkedIn", "http://linkedin.com") 60 | }; 61 | 62 | // Act 63 | var component = context.RenderComponent(parameters); 64 | 65 | // Assert 66 | var socialNetworkDiv = component.Find("div .social-networks"); 67 | 68 | Assert.True(socialNetworkDiv.HasChildNodes); 69 | Assert.Equal(8, socialNetworkDiv.ChildElementCount); // There should be 8 elements (Social Networks) 70 | 71 | Assert.NotNull(component.Find("div .social-networks .fa-globe-americas")); 72 | Assert.NotNull(component.Find("div .social-networks .fa-linkedin")); 73 | Assert.NotNull(component.Find("div .social-networks .fa-twitter")); 74 | Assert.NotNull(component.Find("div .social-networks .fa-github")); 75 | Assert.NotNull(component.Find("div .social-networks .fa-paper-plane")); 76 | Assert.NotNull(component.Find("div .social-networks .fa-stack-overflow")); 77 | Assert.NotNull(component.Find("div .social-networks .fa-medium")); 78 | Assert.NotNull(component.Find("div .social-networks .fa-youtube")); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | In the interest of fostering an open and welcoming environment, we as 7 | contributors and maintainers pledge to making participation in our project and 8 | our community a harassment-free experience for everyone, regardless of age, body 9 | size, disability, ethnicity, sex characteristics, gender identity and expression, 10 | level of experience, education, socio-economic status, nationality, personal 11 | appearance, race, religion, or sexual identity and orientation. 12 | 13 | ## Our Standards 14 | 15 | Examples of behavior that contributes to creating a positive environment 16 | include: 17 | 18 | * Using welcoming and inclusive language 19 | * Being respectful of differing viewpoints and experiences 20 | * Gracefully accepting constructive criticism 21 | * Focusing on what is best for the community 22 | * Showing empathy towards other community members 23 | 24 | Examples of unacceptable behavior by participants include: 25 | 26 | * The use of sexualized language or imagery and unwelcome sexual attention or 27 | advances 28 | * Trolling, insulting/derogatory comments, and personal or political attacks 29 | * Public or private harassment 30 | * Publishing others' private information, such as a physical or electronic 31 | address, without explicit permission 32 | * Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | ## Our Responsibilities 36 | 37 | Project maintainers are responsible for clarifying the standards of acceptable 38 | behavior and are expected to take appropriate and fair corrective action in 39 | response to any instances of unacceptable behavior. 40 | 41 | Project maintainers have the right and responsibility to remove, edit, or 42 | reject comments, commits, code, wiki edits, issues, and other contributions 43 | that are not aligned to this Code of Conduct, or to ban temporarily or 44 | permanently any contributor for other behaviors that they deem inappropriate, 45 | threatening, offensive, or harmful. 46 | 47 | ## Scope 48 | 49 | This Code of Conduct applies both within project spaces and in public spaces 50 | when an individual is representing the project or its community. Examples of 51 | representing a project or community include using an official project e-mail 52 | address, posting via an official social media account, or acting as an appointed 53 | representative at an online or offline event. Representation of a project may be 54 | further defined and clarified by project maintainers. 55 | 56 | ## Enforcement 57 | 58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 59 | reported by contacting the project team at [@_AngelGarcia13](https://twitter.com/_AngelGarcia13), [@JadhielV](https://twitter.com/JadhielV). 60 | All complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 72 | version 2.0, available at 73 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 74 | 75 | [homepage]: https://www.contributor-covenant.org 76 | 77 | For answers to common questions about this code of conduct, see the FAQ at 78 | https://www.contributor-covenant.org/faq. -------------------------------------------------------------------------------- /DWC.Blazor/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 30 |
31 |
32 |

DominicanWho.Codes

33 |

Dominican Developers who like to code and contribute to Open Source

34 |
35 | @Body 36 |
37 | 38 |
39 | 78 |
79 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/twitter-bootstrap/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f5f6fa; 3 | color: #343a40; 4 | } 5 | .navbar-toggler, 6 | .navbar-toggler:focus, 7 | .navbar-toggler:active { 8 | outline: none; 9 | box-shadow: none; 10 | border-color: transparent !important; 11 | background-color: transparent !important; 12 | } 13 | .nav-item { 14 | margin: 0 10px; 15 | } 16 | .card { 17 | border-radius: 0.5rem; 18 | box-shadow: 0 0.75rem 1.5rem rgba(0, 0, 0, 0.03); 19 | -webkit-transition: transform 375ms ease-in-out, box-shadow 375ms ease-out; 20 | transition: transform 375ms ease-in-out, box-shadow 375ms ease-out; 21 | } 22 | .card:hover { 23 | transform: scale(1.05); 24 | z-index: 1000; 25 | background-color: #fff; 26 | box-shadow: 0 0 20px -2px rgba(0, 0, 0, 0.3); 27 | } 28 | .card-img-top { 29 | border-top-left-radius: calc(0.5rem - 1px); 30 | border-top-right-radius: calc(0.5rem - 1px); 31 | -webkit-filter: grayscale(100%); /* Safari 6.0 - 9.0 */ 32 | filter: grayscale(100%); 33 | transition: all 375ms ease-in-out; 34 | width: 100%; 35 | height: 15vw; 36 | object-fit: cover; 37 | object-position: 0 -10px; 38 | } 39 | .card:hover .card-img-top { 40 | -webkit-filter: grayscale(0%); /* Safari 6.0 - 9.0 */ 41 | filter: grayscale(0%); 42 | } 43 | 44 | .avatar-sm { 45 | width: 2.4375rem; 46 | height: 2.4375rem; 47 | font-size: 0.75rem; 48 | border-radius: 0.2rem; 49 | } 50 | .avatar { 51 | position: relative; 52 | color: #fff; 53 | display: inline-flex; 54 | align-items: center; 55 | justify-content: center; 56 | vertical-align: middle; 57 | font-size: 1rem; 58 | font-weight: 600; 59 | height: 3.125rem; 60 | width: 3.125rem; 61 | border-radius: 0.375rem; 62 | } 63 | .badge-pill { 64 | padding: 6px; 65 | } 66 | .info-space { 67 | margin-bottom: 3px; 68 | } 69 | .description-space { 70 | height: 100px; 71 | display: flex; 72 | flex-direction: column; 73 | justify-content: center; 74 | overflow: hidden; 75 | scrollbar-width: thin; 76 | } 77 | .social-networks { 78 | font-size: x-large; 79 | } 80 | 81 | .social-networks a.social-networks-icon { 82 | margin: 8px; 83 | } 84 | 85 | /*@juanchinovas*/ 86 | 87 | #splash-screen { 88 | display: flex; 89 | flex-direction: column; 90 | justify-content: center; 91 | align-items: center; 92 | padding-top: 35vh; 93 | } 94 | 95 | #pulse-animation { 96 | position: relative; 97 | width: 100px; 98 | height: 100px; 99 | opacity: 0; 100 | border: 1.5rem solid #444444; 101 | border-radius: 50%; 102 | animation: pulsate 1s ease-out; 103 | animation-iteration-count: infinite; 104 | } 105 | 106 | span#app-name { 107 | font-size: 1.5rem; 108 | font-weight: bold; 109 | } 110 | 111 | @keyframes pulsate { 112 | 0% { 113 | transform: scale(0.2); 114 | opacity: 0; 115 | } 116 | 50% { 117 | opacity: 1; 118 | } 119 | 100% { 120 | transform: scale(1.5); 121 | opacity: 0; 122 | } 123 | } 124 | #info-skills .info-space .badge { 125 | margin: 0 2px; 126 | } 127 | #info-skills { 128 | margin: 0.3rem 0; 129 | height: 35px; 130 | overflow: hidden; 131 | } 132 | 133 | #info-skills .info-space { 134 | display: flex; 135 | overflow: hidden; 136 | scrollbar-width: thin; 137 | padding: 0.2rem; 138 | } 139 | 140 | .description-space:hover, 141 | #info-skills .info-space:hover { 142 | overflow: auto; 143 | } 144 | 145 | .description-space::-webkit-scrollbar, 146 | #info-skills .info-space::-webkit-scrollbar { 147 | height: 4px; 148 | width: 4px; 149 | } 150 | .description-space::-webkit-scrollbar-track, 151 | #info-skills .info-space::-webkit-scrollbar-track { 152 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 153 | border-radius: 10px; 154 | } 155 | .description-space::-webkit-scrollbar-thumb, 156 | #info-skills .info-space::-webkit-scrollbar-thumb { 157 | border-radius: 10px; 158 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5); 159 | } 160 | 161 | .description-space p { 162 | margin: 0; 163 | } 164 | 165 | .em { 166 | height: 1.5em; 167 | width: 1.5em; 168 | background-position: center; 169 | background-repeat: no-repeat; 170 | background-size: contain; 171 | display: inline-block; 172 | vertical-align: middle; 173 | } 174 | 175 | .em-flag-do { 176 | background-image: url("https://twemoji.maxcdn.com/2/72x72/1f1e9-1f1f4.png"); 177 | } 178 | 179 | .em-heart { 180 | background-image: url("https://twemoji.maxcdn.com/2/72x72/2764.png"); 181 | } 182 | 183 | @media only screen and (max-width: 600px) { 184 | .card-img-top { 185 | height: 80vw; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /DWC.Blazor/Utils/UrlValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DWC.Blazor.Utils 4 | { 5 | public class ValidationResult 6 | { 7 | public bool IsValid { get; set; } 8 | public string ErrorMessage { get; set; } 9 | 10 | public ValidationResult(bool isValid, string errorMessage = "") 11 | { 12 | IsValid = isValid; 13 | ErrorMessage = errorMessage; 14 | } 15 | } 16 | 17 | public static class UrlValidator 18 | { 19 | public static ValidationResult ValidateUrl(string url, string platform) 20 | { 21 | if (string.IsNullOrWhiteSpace(url)) 22 | return new ValidationResult(false, "URL cannot be null or empty."); 23 | 24 | if (string.IsNullOrWhiteSpace(platform)) 25 | return new ValidationResult(false, "Platform cannot be null or empty."); 26 | 27 | // Trim the URL 28 | var trimmedUrl = url.Trim(); 29 | 30 | // Validate URI format and scheme 31 | if (!Uri.TryCreate(trimmedUrl, UriKind.Absolute, out Uri uriResult)) 32 | return new ValidationResult(false, "URL is not a valid URI format."); 33 | 34 | // Check if scheme is http or https (part of format validation) 35 | if (uriResult.Scheme != Uri.UriSchemeHttp && uriResult.Scheme != Uri.UriSchemeHttps) 36 | return new ValidationResult(false, "URL is not a valid URI format."); 37 | 38 | // Validate HTTPS protocol 39 | if (uriResult.Scheme != Uri.UriSchemeHttps) 40 | return new ValidationResult(false, "URL must use HTTPS protocol."); 41 | 42 | // Normalize platform name 43 | var normalizedPlatform = platform.Trim().ToLowerInvariant(); 44 | 45 | // Platform-specific validation 46 | var host = uriResult.Host.ToLowerInvariant(); 47 | var pathAndQuery = uriResult.PathAndQuery.ToLowerInvariant(); 48 | 49 | switch (normalizedPlatform) 50 | { 51 | case "linkedin": 52 | if (!(host == "linkedin.com" || host.EndsWith(".linkedin.com"))) 53 | return new ValidationResult(false, "LinkedIn URL must contain 'linkedin.com/in/' or 'linkedin.com/company/'."); 54 | 55 | if (!pathAndQuery.Contains("/in/") && !pathAndQuery.Contains("/company/")) 56 | return new ValidationResult(false, "LinkedIn URL must contain 'linkedin.com/in/' or 'linkedin.com/company/'."); 57 | break; 58 | 59 | case "github": 60 | if (!(host == "github.com" || host.EndsWith(".github.com"))) 61 | return new ValidationResult(false, "GitHub URL must contain 'github.com/'."); 62 | break; 63 | 64 | case "twitter": 65 | if (!(host == "twitter.com" || host.EndsWith(".twitter.com") || 66 | host == "x.com" || host.EndsWith(".x.com"))) 67 | return new ValidationResult(false, "Twitter URL must contain 'twitter.com/' or 'x.com/'."); 68 | break; 69 | 70 | case "telegram": 71 | if (!host.Equals("t.me")) 72 | return new ValidationResult(false, "Telegram URL must contain 't.me/'."); 73 | break; 74 | 75 | case "stackoverflow": 76 | if (!(host == "stackoverflow.com" || host.EndsWith(".stackoverflow.com"))) 77 | return new ValidationResult(false, "StackOverflow URL must contain 'stackoverflow.com/users/'."); 78 | 79 | if (!pathAndQuery.Contains("/users/")) 80 | return new ValidationResult(false, "StackOverflow URL must contain 'stackoverflow.com/users/'."); 81 | break; 82 | 83 | case "medium": 84 | if (!(host == "medium.com" || host.EndsWith(".medium.com"))) 85 | return new ValidationResult(false, "Medium URL must contain 'medium.com/@'."); 86 | 87 | if (!pathAndQuery.Contains("/@")) 88 | return new ValidationResult(false, "Medium URL must contain 'medium.com/@'."); 89 | break; 90 | 91 | case "youtube": 92 | if (!(host == "youtube.com" || host.EndsWith(".youtube.com") || 93 | host == "youtu.be" || host.EndsWith(".youtu.be"))) 94 | return new ValidationResult(false, "YouTube URL must contain 'youtube.com/' or 'youtu.be/'."); 95 | break; 96 | 97 | case "webpage": 98 | // Any valid HTTPS URL is acceptable for webpage 99 | break; 100 | 101 | default: 102 | return new ValidationResult(false, $"Unknown platform: {platform}."); 103 | } 104 | 105 | return new ValidationResult(true); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/svg-with-js.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | .svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor)}.svg-inline--fa .fa-secondary,.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff} -------------------------------------------------------------------------------- /DWC.Blazor.Tests/SkillNormalizerTests.cs: -------------------------------------------------------------------------------- 1 | using DWC.Blazor.Utils; 2 | using System.Linq; 3 | using Xunit; 4 | 5 | namespace DWC.Blazor.Tests 6 | { 7 | public class SkillNormalizerTests 8 | { 9 | [Fact] 10 | public void Normalize_JavaScript_ReturnsNormalized() 11 | { 12 | // Arrange 13 | var input = "javascript"; 14 | 15 | // Act 16 | var result = SkillNormalizer.Normalize(input); 17 | 18 | // Assert 19 | Assert.Equal("JavaScript", result); 20 | } 21 | 22 | [Theory] 23 | [InlineData("vue", "Vue.js")] 24 | [InlineData("VUE", "Vue.js")] 25 | [InlineData("Vue", "Vue.js")] 26 | [InlineData("vuejs", "Vue.js")] 27 | [InlineData("vue.js", "Vue.js")] 28 | [InlineData("vue js", "Vue.js")] 29 | public void Normalize_VueVariations_ReturnsVueJs(string input, string expected) 30 | { 31 | // Act 32 | var result = SkillNormalizer.Normalize(input); 33 | 34 | // Assert 35 | Assert.Equal(expected, result); 36 | } 37 | 38 | [Theory] 39 | [InlineData(".net", ".NET")] 40 | [InlineData("dotnet", ".NET")] 41 | [InlineData(".NET(C#)", ".NET")] 42 | [InlineData(".net (c#)", ".NET")] 43 | public void Normalize_DotNetVariations_ReturnsDotNet(string input, string expected) 44 | { 45 | // Act 46 | var result = SkillNormalizer.Normalize(input); 47 | 48 | // Assert 49 | Assert.Equal(expected, result); 50 | } 51 | 52 | [Theory] 53 | [InlineData(".net core", ".NET Core")] 54 | [InlineData("dotnet core", ".NET Core")] 55 | [InlineData(".net core c#", ".NET Core")] 56 | public void Normalize_DotNetCoreVariations_ReturnsDotNetCore(string input, string expected) 57 | { 58 | // Act 59 | var result = SkillNormalizer.Normalize(input); 60 | 61 | // Assert 62 | Assert.Equal(expected, result); 63 | } 64 | 65 | [Theory] 66 | [InlineData("asp.net", "ASP.NET")] 67 | [InlineData("aspnet", "ASP.NET")] 68 | [InlineData("asp.net mvc", "ASP.NET")] 69 | public void Normalize_AspNetVariations_ReturnsAspNet(string input, string expected) 70 | { 71 | // Act 72 | var result = SkillNormalizer.Normalize(input); 73 | 74 | // Assert 75 | Assert.Equal(expected, result); 76 | } 77 | 78 | [Theory] 79 | [InlineData("xamarin", "Xamarin")] 80 | [InlineData("xamarin.forms", "Xamarin")] 81 | [InlineData("xamarin.android", "Xamarin")] 82 | public void Normalize_XamarinVariations_ReturnsXamarin(string input, string expected) 83 | { 84 | // Act 85 | var result = SkillNormalizer.Normalize(input); 86 | 87 | // Assert 88 | Assert.Equal(expected, result); 89 | } 90 | 91 | [Fact] 92 | public void Normalize_EmptyString_ReturnsEmpty() 93 | { 94 | // Arrange 95 | var input = ""; 96 | 97 | // Act 98 | var result = SkillNormalizer.Normalize(input); 99 | 100 | // Assert 101 | Assert.Equal(string.Empty, result); 102 | } 103 | 104 | [Fact] 105 | public void Normalize_NullString_ReturnsEmpty() 106 | { 107 | // Arrange 108 | string input = null; 109 | 110 | // Act 111 | var result = SkillNormalizer.Normalize(input); 112 | 113 | // Assert 114 | Assert.Equal(string.Empty, result); 115 | } 116 | 117 | [Fact] 118 | public void NormalizeSkills_WithAndSeparator_SplitsSkills() 119 | { 120 | // Arrange 121 | var input = "Angular and TSQL"; 122 | 123 | // Act 124 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 125 | 126 | // Assert 127 | Assert.Equal(2, result.Count); 128 | Assert.Contains("Angular", result); 129 | Assert.Contains("T-SQL", result); 130 | } 131 | 132 | [Fact] 133 | public void NormalizeSkills_WithAmpersandSeparator_SplitsSkills() 134 | { 135 | // Arrange 136 | var input = "C# & VB"; 137 | 138 | // Act 139 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 140 | 141 | // Assert 142 | Assert.Equal(2, result.Count); 143 | Assert.Contains("C#", result); 144 | Assert.Contains("Vb", result); 145 | } 146 | 147 | [Fact] 148 | public void NormalizeSkills_CommaSeparated_ReturnsNormalizedList() 149 | { 150 | // Arrange 151 | var input = "javascript, python, c#"; 152 | 153 | // Act 154 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 155 | 156 | // Assert 157 | Assert.Equal(3, result.Count); 158 | Assert.Contains("JavaScript", result); 159 | Assert.Contains("Python", result); 160 | Assert.Contains("C#", result); 161 | } 162 | 163 | [Fact] 164 | public void NormalizeSkills_EmptyString_ReturnsEmptyList() 165 | { 166 | // Arrange 167 | var input = ""; 168 | 169 | // Act 170 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 171 | 172 | // Assert 173 | Assert.Empty(result); 174 | } 175 | 176 | [Fact] 177 | public void NormalizeSkills_NullString_ReturnsEmptyList() 178 | { 179 | // Arrange 180 | string input = null; 181 | 182 | // Act 183 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 184 | 185 | // Assert 186 | Assert.Empty(result); 187 | } 188 | 189 | [Fact] 190 | public void NormalizeSkills_WithExtraSpaces_TrimsCorrectly() 191 | { 192 | // Arrange 193 | var input = " javascript , python "; 194 | 195 | // Act 196 | var result = SkillNormalizer.NormalizeSkills(input).ToList(); 197 | 198 | // Assert 199 | Assert.Equal(2, result.Count); 200 | Assert.Contains("JavaScript", result); 201 | Assert.Contains("Python", result); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/twitter-bootstrap/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/) 3 | * Copyright 2011-2019 The Bootstrap Authors 4 | * Copyright 2011-2019 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 19 | } 20 | 21 | article, aside, figcaption, figure, footer, header, hgroup, main, nav, section { 22 | display: block; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 28 | font-size: 1rem; 29 | font-weight: 400; 30 | line-height: 1.5; 31 | color: #212529; 32 | text-align: left; 33 | background-color: #fff; 34 | } 35 | 36 | [tabindex="-1"]:focus { 37 | outline: 0 !important; 38 | } 39 | 40 | hr { 41 | box-sizing: content-box; 42 | height: 0; 43 | overflow: visible; 44 | } 45 | 46 | h1, h2, h3, h4, h5, h6 { 47 | margin-top: 0; 48 | margin-bottom: 0.5rem; 49 | } 50 | 51 | p { 52 | margin-top: 0; 53 | margin-bottom: 1rem; 54 | } 55 | 56 | abbr[title], 57 | abbr[data-original-title] { 58 | text-decoration: underline; 59 | -webkit-text-decoration: underline dotted; 60 | text-decoration: underline dotted; 61 | cursor: help; 62 | border-bottom: 0; 63 | -webkit-text-decoration-skip-ink: none; 64 | text-decoration-skip-ink: none; 65 | } 66 | 67 | address { 68 | margin-bottom: 1rem; 69 | font-style: normal; 70 | line-height: inherit; 71 | } 72 | 73 | ol, 74 | ul, 75 | dl { 76 | margin-top: 0; 77 | margin-bottom: 1rem; 78 | } 79 | 80 | ol ol, 81 | ul ul, 82 | ol ul, 83 | ul ol { 84 | margin-bottom: 0; 85 | } 86 | 87 | dt { 88 | font-weight: 700; 89 | } 90 | 91 | dd { 92 | margin-bottom: .5rem; 93 | margin-left: 0; 94 | } 95 | 96 | blockquote { 97 | margin: 0 0 1rem; 98 | } 99 | 100 | b, 101 | strong { 102 | font-weight: bolder; 103 | } 104 | 105 | small { 106 | font-size: 80%; 107 | } 108 | 109 | sub, 110 | sup { 111 | position: relative; 112 | font-size: 75%; 113 | line-height: 0; 114 | vertical-align: baseline; 115 | } 116 | 117 | sub { 118 | bottom: -.25em; 119 | } 120 | 121 | sup { 122 | top: -.5em; 123 | } 124 | 125 | a { 126 | color: #007bff; 127 | text-decoration: none; 128 | background-color: transparent; 129 | } 130 | 131 | a:hover { 132 | color: #0056b3; 133 | text-decoration: underline; 134 | } 135 | 136 | a:not([href]):not([tabindex]) { 137 | color: inherit; 138 | text-decoration: none; 139 | } 140 | 141 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { 142 | color: inherit; 143 | text-decoration: none; 144 | } 145 | 146 | a:not([href]):not([tabindex]):focus { 147 | outline: 0; 148 | } 149 | 150 | pre, 151 | code, 152 | kbd, 153 | samp { 154 | font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 155 | font-size: 1em; 156 | } 157 | 158 | pre { 159 | margin-top: 0; 160 | margin-bottom: 1rem; 161 | overflow: auto; 162 | } 163 | 164 | figure { 165 | margin: 0 0 1rem; 166 | } 167 | 168 | img { 169 | vertical-align: middle; 170 | border-style: none; 171 | } 172 | 173 | svg { 174 | overflow: hidden; 175 | vertical-align: middle; 176 | } 177 | 178 | table { 179 | border-collapse: collapse; 180 | } 181 | 182 | caption { 183 | padding-top: 0.75rem; 184 | padding-bottom: 0.75rem; 185 | color: #6c757d; 186 | text-align: left; 187 | caption-side: bottom; 188 | } 189 | 190 | th { 191 | text-align: inherit; 192 | } 193 | 194 | label { 195 | display: inline-block; 196 | margin-bottom: 0.5rem; 197 | } 198 | 199 | button { 200 | border-radius: 0; 201 | } 202 | 203 | button:focus { 204 | outline: 1px dotted; 205 | outline: 5px auto -webkit-focus-ring-color; 206 | } 207 | 208 | input, 209 | button, 210 | select, 211 | optgroup, 212 | textarea { 213 | margin: 0; 214 | font-family: inherit; 215 | font-size: inherit; 216 | line-height: inherit; 217 | } 218 | 219 | button, 220 | input { 221 | overflow: visible; 222 | } 223 | 224 | button, 225 | select { 226 | text-transform: none; 227 | } 228 | 229 | select { 230 | word-wrap: normal; 231 | } 232 | 233 | button, 234 | [type="button"], 235 | [type="reset"], 236 | [type="submit"] { 237 | -webkit-appearance: button; 238 | } 239 | 240 | button:not(:disabled), 241 | [type="button"]:not(:disabled), 242 | [type="reset"]:not(:disabled), 243 | [type="submit"]:not(:disabled) { 244 | cursor: pointer; 245 | } 246 | 247 | button::-moz-focus-inner, 248 | [type="button"]::-moz-focus-inner, 249 | [type="reset"]::-moz-focus-inner, 250 | [type="submit"]::-moz-focus-inner { 251 | padding: 0; 252 | border-style: none; 253 | } 254 | 255 | input[type="radio"], 256 | input[type="checkbox"] { 257 | box-sizing: border-box; 258 | padding: 0; 259 | } 260 | 261 | input[type="date"], 262 | input[type="time"], 263 | input[type="datetime-local"], 264 | input[type="month"] { 265 | -webkit-appearance: listbox; 266 | } 267 | 268 | textarea { 269 | overflow: auto; 270 | resize: vertical; 271 | } 272 | 273 | fieldset { 274 | min-width: 0; 275 | padding: 0; 276 | margin: 0; 277 | border: 0; 278 | } 279 | 280 | legend { 281 | display: block; 282 | width: 100%; 283 | max-width: 100%; 284 | padding: 0; 285 | margin-bottom: .5rem; 286 | font-size: 1.5rem; 287 | line-height: inherit; 288 | color: inherit; 289 | white-space: normal; 290 | } 291 | 292 | progress { 293 | vertical-align: baseline; 294 | } 295 | 296 | [type="number"]::-webkit-inner-spin-button, 297 | [type="number"]::-webkit-outer-spin-button { 298 | height: auto; 299 | } 300 | 301 | [type="search"] { 302 | outline-offset: -2px; 303 | -webkit-appearance: none; 304 | } 305 | 306 | [type="search"]::-webkit-search-decoration { 307 | -webkit-appearance: none; 308 | } 309 | 310 | ::-webkit-file-upload-button { 311 | font: inherit; 312 | -webkit-appearance: button; 313 | } 314 | 315 | output { 316 | display: inline-block; 317 | } 318 | 319 | summary { 320 | display: list-item; 321 | cursor: pointer; 322 | } 323 | 324 | template { 325 | display: none; 326 | } 327 | 328 | [hidden] { 329 | display: none !important; 330 | } 331 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | .DS_Store 332 | 333 | # Claude Code local settings 334 | .claude/ 335 | -------------------------------------------------------------------------------- /DWC.Blazor.Tests/CsvExportServiceTests.cs: -------------------------------------------------------------------------------- 1 | using DWC.Blazor.Services; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Xunit; 6 | using static DWC.Blazor.Pages.Index; 7 | 8 | namespace DWC.Blazor.Tests 9 | { 10 | public class CsvExportServiceTests 11 | { 12 | private readonly CsvExportService _service; 13 | 14 | public CsvExportServiceTests() 15 | { 16 | _service = new CsvExportService(); 17 | } 18 | 19 | [Fact] 20 | public void ExportDevelopersToCsv_WithValidDevelopers_ReturnsByteArray() 21 | { 22 | // Arrange 23 | var developers = new List 24 | { 25 | new() { 26 | Name = "John Doe", 27 | Skills = "C#, JavaScript, SQL", 28 | Summary = "Santo Domingo, Dominican Republic", 29 | Github = "https://github.com/johndoe", 30 | LinkedIn = "https://linkedin.com/in/johndoe", 31 | Twitter = "https://twitter.com/johndoe", 32 | Webpage = "https://johndoe.dev" 33 | } 34 | }; 35 | 36 | // Act 37 | var result = _service.ExportDevelopersToCsv(developers); 38 | 39 | // Assert 40 | Assert.NotNull(result); 41 | Assert.NotEmpty(result); 42 | 43 | var csv = Encoding.UTF8.GetString(result); 44 | Assert.Contains("Name,Skills,Summary,GitHub,LinkedIn,Twitter,Website", csv); 45 | Assert.Contains("John Doe", csv); 46 | Assert.Contains("C#, JavaScript, SQL", csv); 47 | } 48 | 49 | [Fact] 50 | public void ExportDevelopersToCsv_WithEmptyList_ReturnsEmptyArray() 51 | { 52 | // Arrange 53 | var developers = new List(); 54 | 55 | // Act 56 | var result = _service.ExportDevelopersToCsv(developers); 57 | 58 | // Assert 59 | Assert.NotNull(result); 60 | Assert.Empty(result); 61 | } 62 | 63 | [Fact] 64 | public void ExportDevelopersToCsv_WithNullList_ReturnsEmptyArray() 65 | { 66 | // Arrange 67 | List developers = null; 68 | 69 | // Act 70 | var result = _service.ExportDevelopersToCsv(developers); 71 | 72 | // Assert 73 | Assert.NotNull(result); 74 | Assert.Empty(result); 75 | } 76 | 77 | [Fact] 78 | public void ExportDevelopersToCsv_WithSkillsUsingAnd_FormatsCorrectly() 79 | { 80 | // Arrange 81 | var developers = new List 82 | { 83 | new() { 84 | Name = "Jane Smith", 85 | Skills = "Python and Machine Learning and Data Science", 86 | Summary = "Santiago, Dominican Republic" 87 | } 88 | }; 89 | 90 | // Act 91 | var result = _service.ExportDevelopersToCsv(developers); 92 | 93 | // Assert 94 | Assert.NotNull(result); 95 | var csv = Encoding.UTF8.GetString(result); 96 | Assert.Contains("Python, Machine Learning, Data Science", csv); 97 | } 98 | 99 | [Fact] 100 | public void ExportDevelopersToCsv_WithSkillsUsingAmpersand_FormatsCorrectly() 101 | { 102 | // Arrange 103 | var developers = new List 104 | { 105 | new() { 106 | Name = "Bob Johnson", 107 | Skills = "Java & Spring Boot & Microservices", 108 | Summary = "La Romana, Dominican Republic" 109 | } 110 | }; 111 | 112 | // Act 113 | var result = _service.ExportDevelopersToCsv(developers); 114 | 115 | // Assert 116 | Assert.NotNull(result); 117 | var csv = Encoding.UTF8.GetString(result); 118 | Assert.Contains("Java, Spring Boot, Microservices", csv); 119 | } 120 | 121 | [Fact] 122 | public void ExportDevelopersToCsv_WithSpecialCharactersInName_HandlesCorrectly() 123 | { 124 | // Arrange 125 | var developers = new List 126 | { 127 | new() { 128 | Name = "María José García-López", 129 | Skills = "React, Node.js", 130 | Summary = "Punta Cana, Dominican Republic" 131 | } 132 | }; 133 | 134 | // Act 135 | var result = _service.ExportDevelopersToCsv(developers); 136 | 137 | // Assert 138 | Assert.NotNull(result); 139 | var csv = Encoding.UTF8.GetString(result); 140 | Assert.Contains("María José García-López", csv); 141 | } 142 | 143 | [Fact] 144 | public void ExportDevelopersToCsv_WithCommasInFields_HandlesCorrectly() 145 | { 146 | // Arrange 147 | var developers = new List 148 | { 149 | new() { 150 | Name = "Carlos Pérez", 151 | Skills = "C#, .NET, ASP.NET", 152 | Summary = "Santo Domingo, Dominican Republic" 153 | } 154 | }; 155 | 156 | // Act 157 | var result = _service.ExportDevelopersToCsv(developers); 158 | 159 | // Assert 160 | Assert.NotNull(result); 161 | var csv = Encoding.UTF8.GetString(result); 162 | Assert.Contains("Carlos Pérez", csv); 163 | // Verify the CSV is properly formed (commas in data should be quoted by CsvHelper) 164 | Assert.Contains("C#, .NET, ASP.NET", csv); 165 | } 166 | 167 | [Fact] 168 | public void ExportDevelopersToCsv_WithNullFields_HandlesGracefully() 169 | { 170 | // Arrange 171 | var developers = new List 172 | { 173 | new() { 174 | Name = "Test Developer", 175 | Skills = null, 176 | Summary = null, 177 | Github = null, 178 | LinkedIn = null, 179 | Twitter = null, 180 | Webpage = null 181 | } 182 | }; 183 | 184 | // Act 185 | var result = _service.ExportDevelopersToCsv(developers); 186 | 187 | // Assert 188 | Assert.NotNull(result); 189 | var csv = Encoding.UTF8.GetString(result); 190 | Assert.Contains("Test Developer", csv); 191 | Assert.Contains("Name,Skills,Summary,GitHub,LinkedIn,Twitter,Website", csv); 192 | } 193 | 194 | [Fact] 195 | public void ExportDevelopersToCsv_WithMultipleDevelopers_IncludesAllRecords() 196 | { 197 | // Arrange 198 | var developers = new List 199 | { 200 | new() { Name = "Developer 1", Skills = "JavaScript" }, 201 | new() { Name = "Developer 2", Skills = "Python" }, 202 | new() { Name = "Developer 3", Skills = "Ruby" } 203 | }; 204 | 205 | // Act 206 | var result = _service.ExportDevelopersToCsv(developers); 207 | 208 | // Assert 209 | Assert.NotNull(result); 210 | var csv = Encoding.UTF8.GetString(result); 211 | Assert.Contains("Developer 1", csv); 212 | Assert.Contains("Developer 2", csv); 213 | Assert.Contains("Developer 3", csv); 214 | Assert.Contains("JavaScript", csv); 215 | Assert.Contains("Python", csv); 216 | Assert.Contains("Ruby", csv); 217 | } 218 | 219 | [Fact] 220 | public void ExportDevelopersToCsv_HasCorrectHeaders_InCorrectOrder() 221 | { 222 | // Arrange 223 | var developers = new List 224 | { 225 | new() { Name = "Test Dev" } 226 | }; 227 | 228 | // Act 229 | var result = _service.ExportDevelopersToCsv(developers); 230 | 231 | // Assert 232 | Assert.NotNull(result); 233 | var csv = Encoding.UTF8.GetString(result); 234 | var lines = csv.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries); 235 | Assert.True(lines.Length >= 1); 236 | var header = lines[0].TrimStart('\ufeff'); // Remove BOM if present 237 | Assert.Equal("Name,Skills,Summary,GitHub,LinkedIn,Twitter,Website", header); 238 | } 239 | 240 | [Fact] 241 | public void ExportDevelopersToCsv_WithEmptyStrings_ExportsEmptyValues() 242 | { 243 | // Arrange 244 | var developers = new List 245 | { 246 | new() { 247 | Name = "Empty Fields Dev", 248 | Skills = "", 249 | Summary = "", 250 | Github = "", 251 | LinkedIn = "", 252 | Twitter = "", 253 | Webpage = "" 254 | } 255 | }; 256 | 257 | // Act 258 | var result = _service.ExportDevelopersToCsv(developers); 259 | 260 | // Assert 261 | Assert.NotNull(result); 262 | var csv = Encoding.UTF8.GetString(result); 263 | Assert.Contains("Empty Fields Dev", csv); 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/css/svg-with-js.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | svg:not(:root).svg-inline--fa { 6 | overflow: visible; } 7 | 8 | .svg-inline--fa { 9 | display: inline-block; 10 | font-size: inherit; 11 | height: 1em; 12 | overflow: visible; 13 | vertical-align: -.125em; } 14 | .svg-inline--fa.fa-lg { 15 | vertical-align: -.225em; } 16 | .svg-inline--fa.fa-w-1 { 17 | width: 0.0625em; } 18 | .svg-inline--fa.fa-w-2 { 19 | width: 0.125em; } 20 | .svg-inline--fa.fa-w-3 { 21 | width: 0.1875em; } 22 | .svg-inline--fa.fa-w-4 { 23 | width: 0.25em; } 24 | .svg-inline--fa.fa-w-5 { 25 | width: 0.3125em; } 26 | .svg-inline--fa.fa-w-6 { 27 | width: 0.375em; } 28 | .svg-inline--fa.fa-w-7 { 29 | width: 0.4375em; } 30 | .svg-inline--fa.fa-w-8 { 31 | width: 0.5em; } 32 | .svg-inline--fa.fa-w-9 { 33 | width: 0.5625em; } 34 | .svg-inline--fa.fa-w-10 { 35 | width: 0.625em; } 36 | .svg-inline--fa.fa-w-11 { 37 | width: 0.6875em; } 38 | .svg-inline--fa.fa-w-12 { 39 | width: 0.75em; } 40 | .svg-inline--fa.fa-w-13 { 41 | width: 0.8125em; } 42 | .svg-inline--fa.fa-w-14 { 43 | width: 0.875em; } 44 | .svg-inline--fa.fa-w-15 { 45 | width: 0.9375em; } 46 | .svg-inline--fa.fa-w-16 { 47 | width: 1em; } 48 | .svg-inline--fa.fa-w-17 { 49 | width: 1.0625em; } 50 | .svg-inline--fa.fa-w-18 { 51 | width: 1.125em; } 52 | .svg-inline--fa.fa-w-19 { 53 | width: 1.1875em; } 54 | .svg-inline--fa.fa-w-20 { 55 | width: 1.25em; } 56 | .svg-inline--fa.fa-pull-left { 57 | margin-right: .3em; 58 | width: auto; } 59 | .svg-inline--fa.fa-pull-right { 60 | margin-left: .3em; 61 | width: auto; } 62 | .svg-inline--fa.fa-border { 63 | height: 1.5em; } 64 | .svg-inline--fa.fa-li { 65 | width: 2em; } 66 | .svg-inline--fa.fa-fw { 67 | width: 1.25em; } 68 | 69 | .fa-layers svg.svg-inline--fa { 70 | bottom: 0; 71 | left: 0; 72 | margin: auto; 73 | position: absolute; 74 | right: 0; 75 | top: 0; } 76 | 77 | .fa-layers { 78 | display: inline-block; 79 | height: 1em; 80 | position: relative; 81 | text-align: center; 82 | vertical-align: -.125em; 83 | width: 1em; } 84 | .fa-layers svg.svg-inline--fa { 85 | -webkit-transform-origin: center center; 86 | transform-origin: center center; } 87 | 88 | .fa-layers-text, .fa-layers-counter { 89 | display: inline-block; 90 | position: absolute; 91 | text-align: center; } 92 | 93 | .fa-layers-text { 94 | left: 50%; 95 | top: 50%; 96 | -webkit-transform: translate(-50%, -50%); 97 | transform: translate(-50%, -50%); 98 | -webkit-transform-origin: center center; 99 | transform-origin: center center; } 100 | 101 | .fa-layers-counter { 102 | background-color: #ff253a; 103 | border-radius: 1em; 104 | -webkit-box-sizing: border-box; 105 | box-sizing: border-box; 106 | color: #fff; 107 | height: 1.5em; 108 | line-height: 1; 109 | max-width: 5em; 110 | min-width: 1.5em; 111 | overflow: hidden; 112 | padding: .25em; 113 | right: 0; 114 | text-overflow: ellipsis; 115 | top: 0; 116 | -webkit-transform: scale(0.25); 117 | transform: scale(0.25); 118 | -webkit-transform-origin: top right; 119 | transform-origin: top right; } 120 | 121 | .fa-layers-bottom-right { 122 | bottom: 0; 123 | right: 0; 124 | top: auto; 125 | -webkit-transform: scale(0.25); 126 | transform: scale(0.25); 127 | -webkit-transform-origin: bottom right; 128 | transform-origin: bottom right; } 129 | 130 | .fa-layers-bottom-left { 131 | bottom: 0; 132 | left: 0; 133 | right: auto; 134 | top: auto; 135 | -webkit-transform: scale(0.25); 136 | transform: scale(0.25); 137 | -webkit-transform-origin: bottom left; 138 | transform-origin: bottom left; } 139 | 140 | .fa-layers-top-right { 141 | right: 0; 142 | top: 0; 143 | -webkit-transform: scale(0.25); 144 | transform: scale(0.25); 145 | -webkit-transform-origin: top right; 146 | transform-origin: top right; } 147 | 148 | .fa-layers-top-left { 149 | left: 0; 150 | right: auto; 151 | top: 0; 152 | -webkit-transform: scale(0.25); 153 | transform: scale(0.25); 154 | -webkit-transform-origin: top left; 155 | transform-origin: top left; } 156 | 157 | .fa-lg { 158 | font-size: 1.33333em; 159 | line-height: 0.75em; 160 | vertical-align: -.0667em; } 161 | 162 | .fa-xs { 163 | font-size: .75em; } 164 | 165 | .fa-sm { 166 | font-size: .875em; } 167 | 168 | .fa-1x { 169 | font-size: 1em; } 170 | 171 | .fa-2x { 172 | font-size: 2em; } 173 | 174 | .fa-3x { 175 | font-size: 3em; } 176 | 177 | .fa-4x { 178 | font-size: 4em; } 179 | 180 | .fa-5x { 181 | font-size: 5em; } 182 | 183 | .fa-6x { 184 | font-size: 6em; } 185 | 186 | .fa-7x { 187 | font-size: 7em; } 188 | 189 | .fa-8x { 190 | font-size: 8em; } 191 | 192 | .fa-9x { 193 | font-size: 9em; } 194 | 195 | .fa-10x { 196 | font-size: 10em; } 197 | 198 | .fa-fw { 199 | text-align: center; 200 | width: 1.25em; } 201 | 202 | .fa-ul { 203 | list-style-type: none; 204 | margin-left: 2.5em; 205 | padding-left: 0; } 206 | .fa-ul > li { 207 | position: relative; } 208 | 209 | .fa-li { 210 | left: -2em; 211 | position: absolute; 212 | text-align: center; 213 | width: 2em; 214 | line-height: inherit; } 215 | 216 | .fa-border { 217 | border: solid 0.08em #eee; 218 | border-radius: .1em; 219 | padding: .2em .25em .15em; } 220 | 221 | .fa-pull-left { 222 | float: left; } 223 | 224 | .fa-pull-right { 225 | float: right; } 226 | 227 | .fa.fa-pull-left, 228 | .fas.fa-pull-left, 229 | .far.fa-pull-left, 230 | .fal.fa-pull-left, 231 | .fab.fa-pull-left { 232 | margin-right: .3em; } 233 | 234 | .fa.fa-pull-right, 235 | .fas.fa-pull-right, 236 | .far.fa-pull-right, 237 | .fal.fa-pull-right, 238 | .fab.fa-pull-right { 239 | margin-left: .3em; } 240 | 241 | .fa-spin { 242 | -webkit-animation: fa-spin 2s infinite linear; 243 | animation: fa-spin 2s infinite linear; } 244 | 245 | .fa-pulse { 246 | -webkit-animation: fa-spin 1s infinite steps(8); 247 | animation: fa-spin 1s infinite steps(8); } 248 | 249 | @-webkit-keyframes fa-spin { 250 | 0% { 251 | -webkit-transform: rotate(0deg); 252 | transform: rotate(0deg); } 253 | 100% { 254 | -webkit-transform: rotate(360deg); 255 | transform: rotate(360deg); } } 256 | 257 | @keyframes fa-spin { 258 | 0% { 259 | -webkit-transform: rotate(0deg); 260 | transform: rotate(0deg); } 261 | 100% { 262 | -webkit-transform: rotate(360deg); 263 | transform: rotate(360deg); } } 264 | 265 | .fa-rotate-90 { 266 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; 267 | -webkit-transform: rotate(90deg); 268 | transform: rotate(90deg); } 269 | 270 | .fa-rotate-180 { 271 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; 272 | -webkit-transform: rotate(180deg); 273 | transform: rotate(180deg); } 274 | 275 | .fa-rotate-270 { 276 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; 277 | -webkit-transform: rotate(270deg); 278 | transform: rotate(270deg); } 279 | 280 | .fa-flip-horizontal { 281 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; 282 | -webkit-transform: scale(-1, 1); 283 | transform: scale(-1, 1); } 284 | 285 | .fa-flip-vertical { 286 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; 287 | -webkit-transform: scale(1, -1); 288 | transform: scale(1, -1); } 289 | 290 | .fa-flip-both, .fa-flip-horizontal.fa-flip-vertical { 291 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; 292 | -webkit-transform: scale(-1, -1); 293 | transform: scale(-1, -1); } 294 | 295 | :root .fa-rotate-90, 296 | :root .fa-rotate-180, 297 | :root .fa-rotate-270, 298 | :root .fa-flip-horizontal, 299 | :root .fa-flip-vertical, 300 | :root .fa-flip-both { 301 | -webkit-filter: none; 302 | filter: none; } 303 | 304 | .fa-stack { 305 | display: inline-block; 306 | height: 2em; 307 | position: relative; 308 | width: 2.5em; } 309 | 310 | .fa-stack-1x, 311 | .fa-stack-2x { 312 | bottom: 0; 313 | left: 0; 314 | margin: auto; 315 | position: absolute; 316 | right: 0; 317 | top: 0; } 318 | 319 | .svg-inline--fa.fa-stack-1x { 320 | height: 1em; 321 | width: 1.25em; } 322 | 323 | .svg-inline--fa.fa-stack-2x { 324 | height: 2em; 325 | width: 2.5em; } 326 | 327 | .fa-inverse { 328 | color: #fff; } 329 | 330 | .sr-only { 331 | border: 0; 332 | clip: rect(0, 0, 0, 0); 333 | height: 1px; 334 | margin: -1px; 335 | overflow: hidden; 336 | padding: 0; 337 | position: absolute; 338 | width: 1px; } 339 | 340 | .sr-only-focusable:active, .sr-only-focusable:focus { 341 | clip: auto; 342 | height: auto; 343 | margin: 0; 344 | overflow: visible; 345 | position: static; 346 | width: auto; } 347 | 348 | .svg-inline--fa .fa-primary { 349 | fill: var(--fa-primary-color, currentColor); 350 | opacity: 1; 351 | opacity: var(--fa-primary-opacity, 1); } 352 | 353 | .svg-inline--fa .fa-secondary { 354 | fill: var(--fa-secondary-color, currentColor); 355 | opacity: 0.4; 356 | opacity: var(--fa-secondary-opacity, 0.4); } 357 | 358 | .svg-inline--fa.fa-swap-opacity .fa-primary { 359 | opacity: 0.4; 360 | opacity: var(--fa-secondary-opacity, 0.4); } 361 | 362 | .svg-inline--fa.fa-swap-opacity .fa-secondary { 363 | opacity: 1; 364 | opacity: var(--fa-primary-opacity, 1); } 365 | 366 | .svg-inline--fa mask .fa-primary, 367 | .svg-inline--fa mask .fa-secondary { 368 | fill: black; } 369 | 370 | .fad.fa-inverse { 371 | color: #fff; } 372 | -------------------------------------------------------------------------------- /DWC.Blazor/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @inject HttpClient Http 3 | @inject IJSRuntime JSRuntime 4 | @inject DWC.Blazor.Services.CsvExportService CsvExportService 5 | @using DWC.Blazor.Extensions 6 | @using DWC.Blazor.Utils 7 | 8 |
9 | @if (isLoading) 10 | { 11 |
12 |
13 | Loading... 14 |
15 |

Loading devs info...

16 |
17 | } 18 | else 19 | { 20 | 21 |
22 |
23 | 24 |
25 | 26 | 32 |
33 | 34 | 35 |
36 | 37 | 44 |
45 | 46 | 47 |
48 | 49 | 54 |
55 |
56 | 57 | 58 |
59 |
60 | Showing @(filteredDevelopers?.Count() ?? 0) of @developers.Length developers 61 |
62 |
63 | 68 | @if (!string.IsNullOrWhiteSpace(searchQuery) || !string.IsNullOrWhiteSpace(selectedSkill)) 69 | { 70 | 73 | } 74 |
75 |
76 |
77 | 78 | 79 | @if (filteredDevelopers == null || !filteredDevelopers.Any()) 80 | { 81 |
82 | 92 |
93 | } 94 | else 95 | { 96 | 97 | @foreach (var developer in filteredDevelopers) 98 | { 99 |
100 | 114 |
115 | } 116 | } 117 | } 118 |
119 | 120 | @code { 121 | private Developer[] developers; 122 | private IEnumerable filteredDevelopers; 123 | private HashSet allSkills = new HashSet(); 124 | 125 | private bool isLoading = true; 126 | private string searchQuery = string.Empty; 127 | private string selectedSkill = string.Empty; 128 | private string sortOrder = "random"; 129 | 130 | protected override async Task OnInitializedAsync() 131 | { 132 | await LoadDevelopers(); 133 | } 134 | 135 | private async Task LoadDevelopers() 136 | { 137 | try 138 | { 139 | isLoading = true; 140 | developers = await Http.GetFromJsonAsync("data/developers.json"); 141 | 142 | if (developers != null && developers.Length > 0) 143 | { 144 | ExtractAllSkills(); 145 | 146 | developers = developers.Shuffle().ToArray(); 147 | filteredDevelopers = developers; 148 | } 149 | } 150 | catch (Exception ex) 151 | { 152 | Console.WriteLine($"Error loading developers: {ex.Message}"); 153 | } 154 | finally 155 | { 156 | isLoading = false; 157 | } 158 | } 159 | 160 | private void ExtractAllSkills() 161 | { 162 | allSkills.Clear(); 163 | foreach (var dev in developers) 164 | { 165 | var normalizedSkills = SkillNormalizer.NormalizeSkills(dev.Skills); 166 | foreach (var skill in normalizedSkills) 167 | { 168 | allSkills.Add(skill); 169 | } 170 | } 171 | } 172 | 173 | private void ApplyFilters() 174 | { 175 | var query = developers.AsEnumerable(); 176 | 177 | // Apply search filter 178 | if (!string.IsNullOrWhiteSpace(searchQuery)) 179 | { 180 | var search = searchQuery.ToLower(); 181 | query = query.Where(d => 182 | d.Name?.ToLower().Contains(search) == true || 183 | d.Skills?.ToLower().Contains(search) == true || 184 | d.Summary?.ToLower().Contains(search) == true 185 | ); 186 | } 187 | 188 | // Apply skill filter 189 | if (!string.IsNullOrWhiteSpace(selectedSkill)) 190 | { 191 | query = query.Where(d => 192 | { 193 | var devSkills = SkillNormalizer.NormalizeSkills(d.Skills); 194 | return devSkills.Contains(selectedSkill, StringComparer.OrdinalIgnoreCase); 195 | }); 196 | } 197 | 198 | filteredDevelopers = query.ToList(); 199 | SortDevelopers(); 200 | } 201 | 202 | private void SortDevelopers() 203 | { 204 | filteredDevelopers = sortOrder switch 205 | { 206 | "name-asc" => filteredDevelopers.OrderBy(d => d.Name), 207 | "name-desc" => filteredDevelopers.OrderByDescending(d => d.Name), 208 | "random" => filteredDevelopers.Shuffle(), 209 | _ => filteredDevelopers 210 | }; 211 | } 212 | 213 | private void ClearFilters() 214 | { 215 | searchQuery = string.Empty; 216 | selectedSkill = string.Empty; 217 | ApplyFilters(); 218 | } 219 | 220 | private async Task ExportToCsv() 221 | { 222 | if (filteredDevelopers == null || !filteredDevelopers.Any()) 223 | { 224 | return; 225 | } 226 | 227 | try 228 | { 229 | var csvData = CsvExportService.ExportDevelopersToCsv(filteredDevelopers.ToList()); 230 | var fileName = $"dominican-developers-{DateTime.Now:yyyy-MM-dd}.csv"; 231 | 232 | await JSRuntime.InvokeVoidAsync("downloadFile", fileName, "text/csv", Convert.ToBase64String(csvData)); 233 | } 234 | catch (Exception ex) 235 | { 236 | Console.WriteLine($"Error exporting to CSV: {ex.Message}"); 237 | } 238 | } 239 | 240 | public class Developer 241 | { 242 | public string Name { get; set; } 243 | public string Initials { get; set; } 244 | public string Image { get; set; } 245 | public string Summary { get; set; } 246 | public string Skills { get; set; } 247 | public string Webpage { get; set; } 248 | public string LinkedIn { get; set; } 249 | public string Twitter { get; set; } 250 | public string Github { get; set; } 251 | public string Telegram { get; set; } 252 | public string StackOverflow { get; set; } 253 | public string Medium { get; set; } 254 | public string YouTube { get; set; } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /DWC.Blazor/Utils/SkillNormalizer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DWC.Blazor.Utils 6 | { 7 | public static class SkillNormalizer 8 | { 9 | private static Dictionary _normalizationMap; 10 | 11 | private static Dictionary NormalizationMap 12 | { 13 | get 14 | { 15 | if (_normalizationMap == null) 16 | { 17 | _normalizationMap = new Dictionary 18 | { 19 | { "javascript", "JavaScript" }, 20 | { "python", "Python" }, 21 | { "java", "Java" }, 22 | { "ruby", "Ruby" }, 23 | { "php", "PHP" }, 24 | { "go", "Go" }, 25 | { "swift", "Swift" }, 26 | { "kotlin", "Kotlin" }, 27 | { "elixir", "Elixir" }, 28 | 29 | // Node 30 | { "node", "Node.js" }, 31 | { "nodejs", "Node.js" }, 32 | { "node.js", "Node.js" }, 33 | 34 | // Vue 35 | { "vue", "Vue.js" }, 36 | { "vuejs", "Vue.js" }, 37 | { "vue.js", "Vue.js" }, 38 | { "vue js", "Vue.js" }, 39 | 40 | // React 41 | { "react", "React" }, 42 | { "reactjs", "React" }, 43 | { "react.js", "React" }, 44 | { "react js", "React" }, 45 | 46 | // React Native 47 | { "react native", "React Native" }, 48 | { "rn", "React Native" }, 49 | 50 | // Angular 51 | { "angular", "Angular" }, 52 | { "angularjs", "Angular" }, 53 | { "angular7", "Angular" }, 54 | 55 | // TypeScript 56 | { "typescript", "TypeScript" }, 57 | { "ts", "TypeScript" }, 58 | { "ts/js", "TypeScript" }, 59 | 60 | // C# 61 | { "c#", "C#" }, 62 | { "csharp", "C#" }, 63 | 64 | // .NET 65 | { ".net", ".NET" }, 66 | { "dotnet", ".NET" }, 67 | { ".net(c#)", ".NET" }, 68 | { ".net (c#)", ".NET" }, 69 | 70 | // .NET Core 71 | { ".net core", ".NET Core" }, 72 | { "dotnet core", ".NET Core" }, 73 | { ".net core c#", ".NET Core" }, 74 | 75 | // ASP.NET 76 | { "asp.net", "ASP.NET" }, 77 | { "aspnet", "ASP.NET" }, 78 | { "asp.net mvc", "ASP.NET" }, 79 | { "asp.net (c# + vb)", "ASP.NET" }, 80 | 81 | // ASP.NET Core 82 | { "asp.net core", "ASP.NET Core" }, 83 | 84 | // Xamarin 85 | { "xamarin", "Xamarin" }, 86 | { "xamarin.forms", "Xamarin" }, 87 | { "xamarin.android", "Xamarin" }, 88 | 89 | // SQL 90 | { "sql", "SQL Server" }, 91 | { "tsql", "T-SQL" }, 92 | { "t-sql", "T-SQL" }, 93 | { "sql server", "SQL Server" }, 94 | { "sql server/transact-sql", "SQL Server" }, 95 | 96 | // Cloud 97 | { "azure", "Azure" }, 98 | { "aws", "AWS" }, 99 | 100 | // DevOps 101 | { "docker", "Docker" }, 102 | { "kubernetes", "Kubernetes" }, 103 | { "k8s", "Kubernetes" }, 104 | { "terraform", "Terraform" }, 105 | 106 | // Frameworks 107 | { "laravel", "Laravel" }, 108 | { "laravel framework", "Laravel" }, 109 | { "php(laravel)", "Laravel" }, 110 | { "ruby on rails", "Ruby on Rails" }, 111 | 112 | // Mobile 113 | { "ios", "iOS" }, 114 | { "android", "Android" }, 115 | { "flutter", "Flutter" }, 116 | 117 | // ML/AI 118 | { "tensorflow", "TensorFlow" }, 119 | 120 | // Game Dev 121 | { "unity", "Unity" }, 122 | { "godot", "Godot" }, 123 | 124 | // Blazor 125 | { "blazor", "Blazor" }, 126 | 127 | // Bot Framework 128 | { "bot framework", "Bot Framework" }, 129 | 130 | // Visual Studio App Center 131 | { "appcenter", "Visual Studio App Center" }, 132 | 133 | // Continuous integration 134 | { "ci", "Continuous integration" }, 135 | 136 | // Azure Cognitive Services 137 | { "cognitive services", "Azure Cognitive Services" }, 138 | 139 | // CSS 140 | { "css", "CSS" }, 141 | 142 | // The Elastic Stack (ELK) 143 | { "elk", "ELK" }, 144 | 145 | // Google Cloud 146 | { "gcp", "GCP" }, 147 | 148 | // Java 8 149 | { "java 8+", "Java" }, 150 | 151 | // JavaScrpit/Js 152 | { "javascrpit", "JavaScript" }, 153 | { "js", "JavaScript" }, 154 | 155 | // MVC 156 | { "mvc", "MVC" }, 157 | 158 | // NativeScript 159 | { "nativescript", "NativeScript" }, 160 | 161 | // NestJS 162 | { "nestjs", "NestJS" }, 163 | 164 | // NoSQL 165 | { "no/sql", "NoSQL" }, 166 | 167 | // OpenShift 168 | { "openshift", "OpenShift" }, 169 | 170 | // Raspberry Pi 171 | { "raspberry pi", "Raspberry Pi" }, 172 | 173 | // RESTFul APIs 174 | { "restful apis", "RESTFul APIs" }, 175 | 176 | // Spring Boot 177 | { "spring boot", "Spring Boot" }, 178 | 179 | // Spring Framework 180 | { "spring framework", "Spring Framework" }, 181 | 182 | // Umbraco 183 | { "umbracocms", "Umbraco" }, 184 | 185 | // Visual Basic.NET 186 | { "vb.net", "Visual Basic .NET" }, 187 | 188 | // WordPress 189 | { "wordpress (with seo)", "WordPress" }, 190 | 191 | // WPF 192 | { "wpf", "WPF" }, 193 | 194 | // Oracle SQL 195 | { "oracle sql", "Oracle SQL" }, 196 | }; 197 | } 198 | return _normalizationMap; 199 | } 200 | } 201 | 202 | public static string Normalize(string skill) 203 | { 204 | if (string.IsNullOrWhiteSpace(skill)) 205 | return string.Empty; 206 | 207 | var trimmedSkill = skill.Trim().ToLowerInvariant(); 208 | 209 | if (NormalizationMap.TryGetValue(trimmedSkill, out var normalized)) 210 | return normalized; 211 | 212 | return char.ToUpper(skill[0]) + skill.Substring(1).ToLower(); 213 | } 214 | 215 | public static IEnumerable NormalizeSkills(string skillsString) 216 | { 217 | if (string.IsNullOrWhiteSpace(skillsString)) 218 | yield break; 219 | 220 | var skills = skillsString.Split(',', StringSplitOptions.RemoveEmptyEntries); 221 | 222 | foreach (var skill in skills) 223 | { 224 | var trimmedSkill = skill.Trim(); 225 | 226 | if (trimmedSkill.Contains(" and ", StringComparison.OrdinalIgnoreCase)) 227 | { 228 | var parts = trimmedSkill.Split(new[] { " and " }, StringSplitOptions.RemoveEmptyEntries); 229 | foreach (var part in parts) 230 | { 231 | var normalized = Normalize(part.Trim()); 232 | if (!string.IsNullOrWhiteSpace(normalized)) 233 | { 234 | yield return normalized; 235 | } 236 | } 237 | } 238 | else if (trimmedSkill.Contains(" & ", StringComparison.OrdinalIgnoreCase)) 239 | { 240 | var parts = trimmedSkill.Split(new[] { " & " }, StringSplitOptions.RemoveEmptyEntries); 241 | foreach (var part in parts) 242 | { 243 | var normalized = Normalize(part.Trim()); 244 | if (!string.IsNullOrWhiteSpace(normalized)) 245 | { 246 | yield return normalized; 247 | } 248 | } 249 | } 250 | else 251 | { 252 | var normalized = Normalize(trimmedSkill); 253 | if (!string.IsNullOrWhiteSpace(normalized)) 254 | { 255 | yield return normalized; 256 | } 257 | } 258 | } 259 | } 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/jquery/core.js: -------------------------------------------------------------------------------- 1 | /* global Symbol */ 2 | // Defining this global in .eslintrc.json would create a danger of using the global 3 | // unguarded in another place, it seems safer to define global only for this module 4 | 5 | define( [ 6 | "./var/arr", 7 | "./var/document", 8 | "./var/getProto", 9 | "./var/slice", 10 | "./var/concat", 11 | "./var/push", 12 | "./var/indexOf", 13 | "./var/class2type", 14 | "./var/toString", 15 | "./var/hasOwn", 16 | "./var/fnToString", 17 | "./var/ObjectFunctionString", 18 | "./var/support", 19 | "./var/isFunction", 20 | "./var/isWindow", 21 | "./core/DOMEval", 22 | "./core/toType" 23 | ], function( arr, document, getProto, slice, concat, push, indexOf, 24 | class2type, toString, hasOwn, fnToString, ObjectFunctionString, 25 | support, isFunction, isWindow, DOMEval, toType ) { 26 | 27 | "use strict"; 28 | 29 | var 30 | version = "3.4.1", 31 | 32 | // Define a local copy of jQuery 33 | jQuery = function( selector, context ) { 34 | 35 | // The jQuery object is actually just the init constructor 'enhanced' 36 | // Need init if jQuery is called (just allow error to be thrown if not included) 37 | return new jQuery.fn.init( selector, context ); 38 | }, 39 | 40 | // Support: Android <=4.0 only 41 | // Make sure we trim BOM and NBSP 42 | rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g; 43 | 44 | jQuery.fn = jQuery.prototype = { 45 | 46 | // The current version of jQuery being used 47 | jquery: version, 48 | 49 | constructor: jQuery, 50 | 51 | // The default length of a jQuery object is 0 52 | length: 0, 53 | 54 | toArray: function() { 55 | return slice.call( this ); 56 | }, 57 | 58 | // Get the Nth element in the matched element set OR 59 | // Get the whole matched element set as a clean array 60 | get: function( num ) { 61 | 62 | // Return all the elements in a clean array 63 | if ( num == null ) { 64 | return slice.call( this ); 65 | } 66 | 67 | // Return just the one element from the set 68 | return num < 0 ? this[ num + this.length ] : this[ num ]; 69 | }, 70 | 71 | // Take an array of elements and push it onto the stack 72 | // (returning the new matched element set) 73 | pushStack: function( elems ) { 74 | 75 | // Build a new jQuery matched element set 76 | var ret = jQuery.merge( this.constructor(), elems ); 77 | 78 | // Add the old object onto the stack (as a reference) 79 | ret.prevObject = this; 80 | 81 | // Return the newly-formed element set 82 | return ret; 83 | }, 84 | 85 | // Execute a callback for every element in the matched set. 86 | each: function( callback ) { 87 | return jQuery.each( this, callback ); 88 | }, 89 | 90 | map: function( callback ) { 91 | return this.pushStack( jQuery.map( this, function( elem, i ) { 92 | return callback.call( elem, i, elem ); 93 | } ) ); 94 | }, 95 | 96 | slice: function() { 97 | return this.pushStack( slice.apply( this, arguments ) ); 98 | }, 99 | 100 | first: function() { 101 | return this.eq( 0 ); 102 | }, 103 | 104 | last: function() { 105 | return this.eq( -1 ); 106 | }, 107 | 108 | eq: function( i ) { 109 | var len = this.length, 110 | j = +i + ( i < 0 ? len : 0 ); 111 | return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); 112 | }, 113 | 114 | end: function() { 115 | return this.prevObject || this.constructor(); 116 | }, 117 | 118 | // For internal use only. 119 | // Behaves like an Array's method, not like a jQuery method. 120 | push: push, 121 | sort: arr.sort, 122 | splice: arr.splice 123 | }; 124 | 125 | jQuery.extend = jQuery.fn.extend = function() { 126 | var options, name, src, copy, copyIsArray, clone, 127 | target = arguments[ 0 ] || {}, 128 | i = 1, 129 | length = arguments.length, 130 | deep = false; 131 | 132 | // Handle a deep copy situation 133 | if ( typeof target === "boolean" ) { 134 | deep = target; 135 | 136 | // Skip the boolean and the target 137 | target = arguments[ i ] || {}; 138 | i++; 139 | } 140 | 141 | // Handle case when target is a string or something (possible in deep copy) 142 | if ( typeof target !== "object" && !isFunction( target ) ) { 143 | target = {}; 144 | } 145 | 146 | // Extend jQuery itself if only one argument is passed 147 | if ( i === length ) { 148 | target = this; 149 | i--; 150 | } 151 | 152 | for ( ; i < length; i++ ) { 153 | 154 | // Only deal with non-null/undefined values 155 | if ( ( options = arguments[ i ] ) != null ) { 156 | 157 | // Extend the base object 158 | for ( name in options ) { 159 | copy = options[ name ]; 160 | 161 | // Prevent Object.prototype pollution 162 | // Prevent never-ending loop 163 | if ( name === "__proto__" || target === copy ) { 164 | continue; 165 | } 166 | 167 | // Recurse if we're merging plain objects or arrays 168 | if ( deep && copy && ( jQuery.isPlainObject( copy ) || 169 | ( copyIsArray = Array.isArray( copy ) ) ) ) { 170 | src = target[ name ]; 171 | 172 | // Ensure proper type for the source value 173 | if ( copyIsArray && !Array.isArray( src ) ) { 174 | clone = []; 175 | } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { 176 | clone = {}; 177 | } else { 178 | clone = src; 179 | } 180 | copyIsArray = false; 181 | 182 | // Never move original objects, clone them 183 | target[ name ] = jQuery.extend( deep, clone, copy ); 184 | 185 | // Don't bring in undefined values 186 | } else if ( copy !== undefined ) { 187 | target[ name ] = copy; 188 | } 189 | } 190 | } 191 | } 192 | 193 | // Return the modified object 194 | return target; 195 | }; 196 | 197 | jQuery.extend( { 198 | 199 | // Unique for each copy of jQuery on the page 200 | expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), 201 | 202 | // Assume jQuery is ready without the ready module 203 | isReady: true, 204 | 205 | error: function( msg ) { 206 | throw new Error( msg ); 207 | }, 208 | 209 | noop: function() {}, 210 | 211 | isPlainObject: function( obj ) { 212 | var proto, Ctor; 213 | 214 | // Detect obvious negatives 215 | // Use toString instead of jQuery.type to catch host objects 216 | if ( !obj || toString.call( obj ) !== "[object Object]" ) { 217 | return false; 218 | } 219 | 220 | proto = getProto( obj ); 221 | 222 | // Objects with no prototype (e.g., `Object.create( null )`) are plain 223 | if ( !proto ) { 224 | return true; 225 | } 226 | 227 | // Objects with prototype are plain iff they were constructed by a global Object function 228 | Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; 229 | return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; 230 | }, 231 | 232 | isEmptyObject: function( obj ) { 233 | var name; 234 | 235 | for ( name in obj ) { 236 | return false; 237 | } 238 | return true; 239 | }, 240 | 241 | // Evaluates a script in a global context 242 | globalEval: function( code, options ) { 243 | DOMEval( code, { nonce: options && options.nonce } ); 244 | }, 245 | 246 | each: function( obj, callback ) { 247 | var length, i = 0; 248 | 249 | if ( isArrayLike( obj ) ) { 250 | length = obj.length; 251 | for ( ; i < length; i++ ) { 252 | if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 253 | break; 254 | } 255 | } 256 | } else { 257 | for ( i in obj ) { 258 | if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { 259 | break; 260 | } 261 | } 262 | } 263 | 264 | return obj; 265 | }, 266 | 267 | // Support: Android <=4.0 only 268 | trim: function( text ) { 269 | return text == null ? 270 | "" : 271 | ( text + "" ).replace( rtrim, "" ); 272 | }, 273 | 274 | // results is for internal usage only 275 | makeArray: function( arr, results ) { 276 | var ret = results || []; 277 | 278 | if ( arr != null ) { 279 | if ( isArrayLike( Object( arr ) ) ) { 280 | jQuery.merge( ret, 281 | typeof arr === "string" ? 282 | [ arr ] : arr 283 | ); 284 | } else { 285 | push.call( ret, arr ); 286 | } 287 | } 288 | 289 | return ret; 290 | }, 291 | 292 | inArray: function( elem, arr, i ) { 293 | return arr == null ? -1 : indexOf.call( arr, elem, i ); 294 | }, 295 | 296 | // Support: Android <=4.0 only, PhantomJS 1 only 297 | // push.apply(_, arraylike) throws on ancient WebKit 298 | merge: function( first, second ) { 299 | var len = +second.length, 300 | j = 0, 301 | i = first.length; 302 | 303 | for ( ; j < len; j++ ) { 304 | first[ i++ ] = second[ j ]; 305 | } 306 | 307 | first.length = i; 308 | 309 | return first; 310 | }, 311 | 312 | grep: function( elems, callback, invert ) { 313 | var callbackInverse, 314 | matches = [], 315 | i = 0, 316 | length = elems.length, 317 | callbackExpect = !invert; 318 | 319 | // Go through the array, only saving the items 320 | // that pass the validator function 321 | for ( ; i < length; i++ ) { 322 | callbackInverse = !callback( elems[ i ], i ); 323 | if ( callbackInverse !== callbackExpect ) { 324 | matches.push( elems[ i ] ); 325 | } 326 | } 327 | 328 | return matches; 329 | }, 330 | 331 | // arg is for internal usage only 332 | map: function( elems, callback, arg ) { 333 | var length, value, 334 | i = 0, 335 | ret = []; 336 | 337 | // Go through the array, translating each of the items to their new values 338 | if ( isArrayLike( elems ) ) { 339 | length = elems.length; 340 | for ( ; i < length; i++ ) { 341 | value = callback( elems[ i ], i, arg ); 342 | 343 | if ( value != null ) { 344 | ret.push( value ); 345 | } 346 | } 347 | 348 | // Go through every key on the object, 349 | } else { 350 | for ( i in elems ) { 351 | value = callback( elems[ i ], i, arg ); 352 | 353 | if ( value != null ) { 354 | ret.push( value ); 355 | } 356 | } 357 | } 358 | 359 | // Flatten any nested arrays 360 | return concat.apply( [], ret ); 361 | }, 362 | 363 | // A global GUID counter for objects 364 | guid: 1, 365 | 366 | // jQuery.support is not used in Core but other projects attach their 367 | // properties to it so it needs to exist. 368 | support: support 369 | } ); 370 | 371 | if ( typeof Symbol === "function" ) { 372 | jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; 373 | } 374 | 375 | // Populate the class2type map 376 | jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 377 | function( i, name ) { 378 | class2type[ "[object " + name + "]" ] = name.toLowerCase(); 379 | } ); 380 | 381 | function isArrayLike( obj ) { 382 | 383 | // Support: real iOS 8.2 only (not reproducible in simulator) 384 | // `in` check used to prevent JIT error (gh-2145) 385 | // hasOwn isn't used here due to false negatives 386 | // regarding Nodelist length in IE 387 | var length = !!obj && "length" in obj && obj.length, 388 | type = toType( obj ); 389 | 390 | if ( isFunction( obj ) || isWindow( obj ) ) { 391 | return false; 392 | } 393 | 394 | return type === "array" || length === 0 || 395 | typeof length === "number" && length > 0 && ( length - 1 ) in obj; 396 | } 397 | 398 | return jQuery; 399 | } ); 400 | -------------------------------------------------------------------------------- /DWC.Blazor/wwwroot/font-awesome/js/conflict-detection.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 4 | */ 5 | var e,t;e=this,t=function(e){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(r){for(var e=1;e>16)+(t>>16)+(n>>16)<<16|65535&n}function a(e,t,n,o,r,i){return u((c=u(u(t,e),u(o,i)))<<(a=r)|c>>>32-a,n);var c,a}function d(e,t,n,o,r,i,c){return a(t&n|~t&o,e,t,r,i,c)}function m(e,t,n,o,r,i,c){return a(t&o|n&~o,e,t,r,i,c)}function h(e,t,n,o,r,i,c){return a(t^n^o,e,t,r,i,c)}function g(e,t,n,o,r,i,c){return a(n^(t|~o),e,t,r,i,c)}function s(e,t){var n,o,r,i,c;e[t>>5]|=128<>>9<<4)]=t;var a=1732584193,s=-271733879,f=-1732584194,l=271733878;for(n=0;n>5]>>>t%32&255);return n}function l(e){var t,n=[];for(n[(e.length>>2)-1]=void 0,t=0;t>5]|=(255&e.charCodeAt(t/8))<>>4&15)+o.charAt(15&t);return r}function n(e){return unescape(encodeURIComponent(e))}function r(e){return f(s(l(t=n(e)),8*t.length));var t}function i(e,t){return function(e,t){var n,o,r=l(e),i=[],c=[];for(i[15]=c[15]=void 0,16 element that loads this detection:"),console.info("\t%c".concat(A,"%c: milliseconds to wait for each test before deciding whether it's a conflict."),"font-weight: bold;","font-size: normal;"),console.info("\t%c".concat(T,"%c: milliseconds to wait for the browser to accumulate test results before giving up."),"font-weight: bold;","font-size: normal;"),D({maxDuration:c,showProgress:!0,progressIndicator:"waiting...",fn:function(){return Object.keys(n.conflict).length+Object.keys(n.noConflict).length>=i}}).then(function(){console.info("DONE!"),E({nodesTested:n,nodesFound:r}),t({nodesTested:n,nodesFound:r}),console.groupEnd()}).catch(function(e){"timeout"===e?console.info("TIME OUT! We waited until we got tired. Here's what we found:"):(console.info("Whoops! We hit an error:",e),console.info("Here's what we'd found up until that error:")),E({nodesTested:n,nodesFound:r}),t({nodesTested:n,nodesFound:r}),console.groupEnd()}))}var F=l.FontAwesomeDetection||{},O=a({},{report:function(e){var t=e.nodesTested,n=e.nodesFound,o={};for(var r in n)t.conflict[r]||t.noConflict[r]||(o[r]=n[r]);var i=Object.keys(t.conflict).length;if(0